IntroductionMachine Learning的本质就是寻找一个function前沿研究RegressionMachine Learning的三个步骤Step1:Model (function set)Linear Model 线性模型Step2:Goodness of FunctionLoss function 损失函数Step3:Pick the Best FunctionGradient Descent 梯度下降单个参数的问题两个参数的问题Gradient Descent的缺点OverfittingConclusion总结关于pokemon的cp值预测的流程总结:Where does the error come from?抽样分布和 真值和估测值抽样分布的理论(概率论与数理统计)用样本均值估测总体期望用样本方差估测总体方差regression的error来自取决于model的复杂程度以及data的数量的variance取决于model的复杂程度和data的数量的bias只取决于model的复杂程度因此为什么会这样?Bias vs Variancebias和variance对error的影响必须要知道自己的error主要来自于哪里你现在的问题是bias大,还是variance大?如何针对性地处理bias大 or variance大的情况呢?如果bias比较大如果variance比较大Model Selectiontraining data分成training set和validation set真正的error如何划分training set和validation set?N-flod Cross ValidationConclusionGradient DescentGradient DescentLearning rate存在的问题learning rate的大小Adaptive Learning ratesAdagradContradictionStochastic Gradicent DescentMini-batch Gradicent DescentBatch size and Training Speedbatch size太小会导致不稳定,速度上也没有优势batch size会受到GPU平行加速的限制,太大可能导致在train的时候卡住不同batch size在梯度下降上的表现GPU是如何平行加速的Feature Scaling对gradient decent的帮助如何做feature scalingGradient Descent的理论基础Taylor SeriesFormal DerivationGradient Descent的限制Classification: Probabilistic Generative ModelClassificationHow to classificationClassification as Regression?Ideal AlternativesFunction(Model)Loss functionSolution:Generative modelPrior ProbabilityProbability from ClassGaussian DistributionDo ClassificationModifying ModelThree Steps of classificationProbability distributionWhy Gaussian distributionNaive Bayes ClassifierPosterior ProbabilityLogistic RegressionStep 1:Function SetStep 2:Goodness of a functionStep 3:Find the best functionLogistic Regression & Linear RegressionCompare In Step 1Compare In Step 2Compare In Step 3Logistic Regression + Square Error?Discriminative & GenerativeExampleBenefit of generative modelConclusionMulti-class ClassificationSoftmaxMulti-class ClassificationLimitation of Logistic RegressionFeature TransformationDeep LearningUps and downs of Deep LearningNeural NetworkConceptFully Connect Feedforward NetworkMatrix OperationOutput LayerExample ApplicationHandwriting Digit RecognitionStep 1:Neural Network常见问题Step 2:Goodness of functionStep 3:Pick the best functionToolkitWhy Deep?Design network structure V.s. Feature EngineeringBackpropagationGradient DescentChain RuleForward passBackward pass公式推导另一个观点两种情况Case 1:Output LayerCase 2:Not Output LayerSummaryTips for Deep LearningRecipe of Deep Learning3 step of deep learningGood Results on Training Data?Good Results on Testing Data?Do not always blame overfittingConclusionGood Results on Training Data?New activation functionactivation functionVanishing Gradient ProblemReLUIntroductionHandle Vanishing gradient problemReLU-variantMaxoutIntroductionMaxoutReLUMaxoutMore than ReLUPropertyHow to train MaxoutAdaptive learning rateReview - AdagradRMSProplearning ratehow to do RMSPropMomentumoptimization - local minima?where is Momentum fromHow to do MomentumAdamGood Results on Testing Data?Early StoppingRegularizationL2 regularizationL1 regularizationL1 V.s. L2Weight Decaysome tipsDropoutHow to do DropoutTrainingTestingWhy Dropout?为什么dropout会有用?为什么training和testing使用的weight是不一样的呢?Dropout is a kind of ensembleensemble精神的解释为什么dropout是一个终极的ensemble方法呢?实际操作ensemble的做法举例说明dropout和ensemble的关系Why Deep?Shallow V.s. DeepDeep is Better?Fat + Short v.s. Thin + TallModularizationintroductionexampleDeep modularizationModularization - ImageModularization - SpeechThe hierarchical structure of human languagesThe first stage of speech recognitionClassification传统做法思考DNN做法ResultAnalogyLogic Circuit剪窗花End-to-end LearningIntroductionSpeech RecognitionComplex TaskConclusionTo learn more …Convolutional Neural NetworkWhy CNN for Image?CNN V.s. DNNThree Property for CNN theory baseSome patterns are much smaller than the whole imageThe same patterns appear in different regionsSubsampling the pixels will not change the objectThe whole CNN structureConvolutionProperty 1Property 2Feature MapColorful imageConvolution V.s. Fully connectedTrainingMax PoolingOperation of max poolingConvolution + Max Pooling过程描述一个重要的问题FlattenWhat does CNN learn?Deep DreamDeep StyleApplicationPlaying GoWhat does CNN do in Playing GoWhy CNN for Playing GoMax Pooling for Alpha Go?——read alpha-go paperSpeech TextReferenceRecurrent Neural NetworkIntroductionSlot FillingSlot Filling with RNNDeeper RNNElman Network & Jordan NetworkBidirectional RNNLSTMThree-gateMemory CellLSTM ExampleLSTM StructureLSTM for RNNLearning TargetLoss FunctionTrainingError SurfaceHelp TechniquesMore ApplicationsSentiment AnalysisKey term ExtractionSpeech RecognitionSequence to Sequence LearningMachine TranslationSyntatic ParsingSequence-to-sequence for Auto-encoder - TextSequence-to-sequence for Auto-encoder - SpeechAttention-based ModelSemi-supervised LearningIntroductionWhy semi-supervised learning help?Semi-supervised Learning for Generative ModelSupervised Generative ModelSemi-supervised Generative ModelLow-density Separation AssumptionSelf TrainingEntropy-based RegularizationSemi-supervised SVMSmoothness AssumptionConceptsDigits DetectionFile ClassificationCluster and then labelGraph-based ApproachBetter RepresentationWord EmbeddingIntroduction1-of-N EncodingWord ClassWord EmbeddingWord EmbeddingCount basedPrediction basedhow to do perdition Why prediction worksSharing ParametersFormulationIn PracticeVarious ArchitecturesOthersApplicationWord EmbeddingMulti-lingual EmbeddingMulti-domain EmbeddingDocument EmbeddingExplainable Machine LearningWhy we need Explainable ML?My Point of ViewInterpretable v.s.PowerfulLocal Explanation: Explain the DecisionIdeaTo Learn More……Limitation of Gradient based Approaches Gradient SaturationAttack InterpretationCase Study: Pokémon v.s. DigimonGlobal Explanation: Explain the whole modelActivation MaximizationConstraint from GeneratorUsing A Model to Explain AnotherLocal Interpretable Model-Agnostic Explanations (LIME)LIME - ImageDecision TreeAdversarial AttackMotivationAttackWhat do we want to do?Loss Function for AttackConstraintHow to AttackExampleWhat happened?Attack ApproachesFast Gradient Sign Method (FGSM)White Box v.s. Black BoxBlack Box AttackUniversal Adversarial AttackAdversarial ReprogrammingAttack in the Real WorldBeyond ImagesDefensePassive DefenseFeature SqueezeRandomization at Inference PhaseProactive DefenseNetwork CompressionNetwork PruningNetwork can be prunedWhy Pruning?Practical IssueWeight pruningNeuron pruningKnowledge DistillationTemperatureParameter QuantizationArchitecture DesignLow rank approximationStandard CNNDepthwise Separable ConvolutionDepthwise ConvolutionPointwise Convolution比较To learn more ……Dynamic ComputationPossible SolutionsConditional Generation by RNN & AttentionGenerationConditional GenerationAttentionDynamic Conditional GenerationAttention-based modelMachine TranslationSpeech RecognitionImage Caption GenerationMemory NetworkNeural Turing MachineTips for GenerationAttentionMismatch between Train and TestModifying Training Process?Scheduled SamplingBeam SearchBetter Idea?Object level v.s. Component levelReinforcement learning?Pointer NetworkApplicationsSummarizationMachine Translation \ Chat-botRecursive StructureApplication: Sentiment AnalysisRecursive ModelMatrix-Vector Recursive NetworkTree LSTMMore ApplicationsTransformerSelf-Attention步骤矩阵运算Multi-head Self-attentionPositional EncodingSeq2seq with AttentionTransformerAttention VisualizationExample ApplicationUniversal TransformerSelf-Attention GANPrinciple Component AnalysisUnsupervised LearningClusteringK-meansHACDimension ReductionWhy Dimension Reduction Help?How to do Dimension Reduction?PCALagrange multiplierCalculate Calculate DecorrelationReconstruction ComponentNeural NetworkWeaknessApplicationPokémonMNISTFaceWhat happens to PCANMFIntroductionMNISTFaceMore Related ApproachesMatrix FactorizationIntroductionMatrix ExpressionPredictionMore about Matrix FactorizationLatent Semantic AnalysisNeighbor EmbeddingManifold LearningLocally Linear EmbeddingLaplacian EigenmapsIntroductionReview for Smoothness AssumptionApplication in Unsupervised Taskt-SNEShortage in LLEHow t-SNE worksKL DivergenceHow to useSimilarity MeasureConclusionDeep Auto-encoderCompare with PCADeep Auto-encoderMulti LayerVisualizeText RetrievalBag-of-wordAuto-encoderSimilar Image SearchPre-trainingGreedy Layer-wise Pre-trainingDe-noising Auto-encoderContractive Auto-encoderRestricted Boltzmann MachineDeep Belief NetworkAuto-encoder for CNNUnpoolingDeconvolutionSeq2Seq Auto-encoderGenerateMore About Auto-encoderMore than minimizing reconstruction errorWhat is good embedding?Beyond ReconstructionSequential DataSkip thoughtQuick thoughtContrastive Predictive Coding (CPC)More interpretable embeddingFeature DisentangleVoice ConversionAdversarial TrainingDesigned Network ArchitectureDiscrete RepresentationEasier to interpret or clusteringVector Quantized Variational Auto-encoder (VQVAE)Sequence as EmbeddingTree as EmbeddingConcluding RemarksBERTRepresentation of Word1-of-N EncodingWord ClassWord EmbeddingA word can have multiple sensesEmbeddings from Language Model (ELMO)Bidirectional Encoder Representations from Transformers (BERT)Training of BERTMasked LMNext Sentence Prediction How to use BERTCase 1Case 2Case 3Case 4 Enhanced Representation through Knowledge Integration (ERNIE)What does BERT learn?Multilingual BERTGenerative Pre-Training (GPT) Zero-shot Learning?VisualizationAnomaly DetectionProblem FormulationWhat is Anomaly?ApplicationsFraud DetectionNetwork Intrusion DetectionCancer DetectionBinary Classification?CategoriesWith labelsWithout labelsCase 1: With ClassifierHow to use the ClassifierHow to estimate ConfidenceNetwork for Confidence EstimationExample FrameworkTraining SetDev SetTesting SetEvaluationCase 2: Without LabelsTwitch Plays PokémonMaximum LikelihoodGaussian DistributionMore FeaturesOutlook: Auto-encoderMore …Concluding RemarksGenerative Adversarial NetworkThree Categories of GANTypical GANAlgorithmGAN is hard to train…Conditional GANText-to-ImageTraditional supervised approachConditional GANSound-to-imageImage-to-labelTalking Head Unsupervised Conditional GANCycle GANSpeech RecognitionConcluding RemarksFlow-based Generative ModelGenerative ModelsGeneratorMath BackgroundJacobian MatrixDeterminantChange of Variable TheoremFormal ExplanationWhat you actually do?Coupling LayerInverseJacobianStacking像素维度划分/通道维度划分1×1 convolution layerDemo of OpenAITo Learn More ……Transfer LearningCase 1Model Fine-tuningConservation TrainingLayer TransferDemoMultitask LearningMultilingual Speech RecognitionProgressive Neural NetworkCase 2Domain-adversarial TrainingZero-shot LearningAttribute embedding Attribute embedding + word embeddingConvex Combination of Semantic EmbeddingExample of Zero-shot LearningCase 3 & 4Concluding Remarks Meta LearningThree Step of Meta-LearningDefine a set of learning algorithmDefine the goodness of a function FFind the best function Omniglot CorpusFew-shot ClassificationTechniques TodayMAMLMAML v.s. Model Pre-trainingOne-Step TrainingToy ExampleOmniglot & Mini-ImageNetfirst-order approximationReal ImplementationTranslationReptileMore...Think about it...Crazy Idea?Gradient Descent as LSTMReview: RNNReview: LSTMSimilar to gradient descent based algorithmLSTM for Gradient DescentReal ImplementationExperimental ResultsLSTM for Gradient Descent (v2)Experimental Result 2Metric-basedSiamese NetworkIntuitive ExplanationTo learn more...N-way Few/One-shot Learning Prototypical NetworkMatching NetworkRelation NetworkFew-shot learning for Imaginary DataMeta Learning-Train+Test as RNNLife-long LearningKnowledge RetentionExample - ImageExample - Question AnsweringCatastrophic ForgettingElastic Weight Consolidation (EWC)Experiment VariantGenerating DataAdding New ClassesKnowledge TransferLife-Long v.s. TransferEvaluationGradient Episodic Memory (GEM)Model ExpansionProgressive Neural NetworksExpert GateNet2NetCurriculum LearningDeep Reinforcement LearningScenario of Reinforcement LearningSupervised v.s. Reinforcement Learning a chat-botInteractive retrievalMore applicationsPlaying Video GameDifficulties of Reinforcement LearningOutlineApproachReferencePolicy-based ApproachNeural Network as ActorGoodness of ActorPick the best functionPolicy GradientValue-based ApproachCriticState value function How to estimate Monte-Carlo based approachTemporal-difference approachState-action value function DQN(Deep Q-Learning)Actor-CriticInverse Reinforcement LearningSupport Vector MachineHinge LossBinary Classificationideal losssquare losssigmoid + square losssigmoid + cross entropycross entropy VS square errorHinge LossLinear SVMmodel descriptiongradient descentanother formulationKernel Methodexplain linear combinationredefine model and loss functionKernel TrickRBF KernelSigmoid KernelDesign Kernel FunctionSVM related methodsSVM vs Deep LearningUnsupervised Learning: GenerationIntroductionPixelRNNIntroductionpokemon creationVariational Autoencoder(VAE)IntroductionPokémon CreationWrite PoetryWhy VAE?Gaussian Mixture ModelMaximizing LikelihoodConnection with Networkproblems of VAEGANIn practical ……EnsembleFramework of EnsembleGet a set of classifiersAggregate the classifiers (properly)BaggingDecision TreeExperiment: Function of MikuRandom ForestBoostingHow to obtain different classifiers?AdaboostRe-weighting Training DataAlgorithm for AdaBoostToy exampleProofMarginExperiment: Function of MikuGradient BoostingStackingStructured LearningExample ApplicationUnified FrameworkObject DetectionSummarizationRetrievalStatisticsThree ProblemsProblem 1: EvaluationProblem 2: InferenceProblem 3: TrainingLink to DNN?Structured Linear ModelSolutionProblem 1Object DetectionSummarizationRetrievalProblem 2Problem 3AlgorithmStructured SVMExample Task: Object DetectionAssumption: SeparableStructured PerceptronProof of TerminationHow to make training fast?Non-separable CaseDefining Cost Function(Stochastic) Gradient DescentConsidering ErrorsDefining Error FunctionAnother Cost FunctionGradient DescentAnother ViewpointMore Cost FunctionsRegularizationStructured SVMIntuitionCutting Plane Algorithm for Structured SVMCutting Plane AlgorithmFind the most violated oneMulti-class and binary SVMMulti-class SVMBinary SVMBeyond Structured SVMSequence Labeling ProblemSequence LabelingExample TaskHidden Markov Model (HMM)How to generate a sentence?Estimating the probabilitiesHow to do POS Tagging?Viterbi AlgorithmHMM - SummaryEvaluationInferenceTrainingHMM - DrawbacksConditional Random Field (CRF) for CRFExampleFeature VectorCRF – Training CriterionGradient AscentCRF - TrainingCRF – InferenceCRF v.s. HMMSynthetic DataComparing HMM and CRFCRF - SummaryStructured PerceptronStructured Perceptron v.s. CRFStructured PerceptronCRFStructured SVMError FunctionPerformance of Different ApproachesRNN v.s. Structured LearningRNN, LSTMHMM, CRF, Structured Perceptron/SVMIntegrated TogetherIs Structure learning practical?Concluding RemarksLearning Map
首先要做的是明确你要找什么样的function,大致上分为以下三类:
Regression——让机器输出一个数值,如预测PM2.5
Classification——让机器做选择题
Generation——让机器去创造、生成
其次是要告诉机器你想要找什么样的function,分为以下三种方式:
接下来就是机器如何去找出你想要的function
当机器知道要找什么样的function之后,就要决定怎么去找这个function,也就是使用loss去衡量一个function的好坏
第一步,给定function寻找的范围
比如Linear Function、Network Architecture都属于指定function的范围
两个经典的Network Architecture就是RNN(会用到Seq2Seq的架构里)和CNN(会用到大部分其他的架构里)
第二步,确定function寻找的方法
主要的方法就是gradient descent以及它的扩展
可以手写实现,也可以用现成的Deep Learning Framework——PyTorch来实现
Explainable AI
举例来说,对猫的图像识别,Explained AI要做的就是让机器告诉我们为什么它觉得这张图片里的东西是猫 (用CNN)
Adversarial Attack
举例来说,现在的图像识别系统已经相当的完善,甚至可以在有诸多噪声的情况下也能成功识别,而Adversarial Attack要做的事情是专门针对机器设计噪声,刻意制造出那些对人眼影响不大,却能够对机器进行全面干扰使之崩溃的噪声图像 (用CNN)
Network Compression
举例来说,你可能有一个识别准确率非常高的model,但是它庞大到无法放到手机、平板里面,而Network Compression要做的事情是压缩这个硕大无比的network,使之能够成功部署在手机甚至更小的平台上 (用CNN)
Anomaly Detection
举例来说,如果你训练了一个识别动物的系统,但是用户放了一张动漫人物的图片进来,该系统还是会把这张图片识别成某种动物,因此Anomaly Detection要做的事情是,让机器知道自己无法识别这张图片,也就是能不能让机器知道“我不知道”
Transfer Learning (即Domain Adversarial Learning)
在用于学习的过程中,训练资料和测试资料的分布往往是相同的,因此能够得到比较高的准确率,比如黑白的手写数字识别,但是在实际场景的应用中,用户给你的测试资料往往和你用来训练的资料很不一样,比如一张彩色背景分布的数字图,此时原先的系统的准确率就会大幅下降,而Transfer Learning要做的事情是,在训练资料和测试资料很不一样的情况下,让机器也能学到东西
Meta Learning
Meta Learning的思想就是让机器学习该如何学习,也就是Learn to learn,传统的机器学习方法是人所设计的,是我们赋予了机器学习的能力;而Meta Learning并不是让机器直接从我们指定好的function范围中去学习,而是让它自己有能力自己去设计一个function的架构,然后再从这个范围内学习到最好的function,我们期待用这种方式让机器自己寻找到那个最合适的model,从而得到比人类指定model的方法更为有效的结果
传统:我们指定model->机器从这个model中学习出best function
Meta:我们教会机器设计model的能力->机器自己设计model->机器从这个model中学习出best function
原因:人为指定的model实际上效率并不高,我们常常见到machine在某些任务上的表现比较好,但是这是它花费大量甚至远超于人类所需的时间和资料才能达到和人类一样的能力;相当于我们指定的model直接定义了这是一个天资不佳的机器,只能通过让它勤奋不懈的学习才能得到好的结果;由于人类的智慧有限无法设计高效的model才导致机器学习效率低下,因此Meta learning就期望让机器自己去定义自己的天赋,从而具备更高效的学习能力
Life-long Learning
一般的机器学习都是针对某一个任务设计的model,而life-long learning想要让机器能够具备终身学习的能力,让它不仅能够学会处理任务1,还能接着学会处理任务2、3...也就是让机器成为一个全能型人才
y代表进化后的cp值,代表进化前的cp值,w和b代表未知参数,可以是任何数值
根据不同的w和b,可以确定不同的无穷无尽的function,而这个抽象出来的式子就叫做model,是以上这些具体化的function的集合,即function set
实际上这是一种Linear Model,我们可以将其扩展为:
xi: an attribute of input X ( xi is also called feature,即特征值)
wi:weight of xi
b: bias
:用上标来表示一个完整的object的编号,表示第i只宝可梦(下标表示该object中的component)
:用表示一个实际观察到的object输出,上标为i表示是第i个object
注:由于regression的输出值是scalar,因此里面并没有component,只是一个简单的数值;但是未来如果考虑structured Learning的时候,我们output的object可能是有structured的,所以我们还是会需要用上标下标来表示一个完整的output的object和它包含的component
为了衡量function set中的某个function的好坏,我们需要一个评估函数,即Loss function,损失函数;Loss function是一个function的function
input:a function;
output:how bad/good it is
由于,即f是由b和w决定的,因此Loss function实际上是在衡量一组参数的好坏
最常用的方法就是采用类似于方差和的形式来衡量参数的好坏,即预测值与真值差的平方和;这里真正的数值减估测数值的平方,叫做估测误差,Estimation error,将10个估测误差合起来就是loss function
如果越大,说明该function表现得越不好;越小,说明该function表现得越好
挑选最好的function这一件事情,写成formulation/equation的样子如下:
,或者是
也就是那个使最小的或,就是我们要找的或(有点像极大似然估计的思想)
只要是可微分的,Gradient Descent都可以拿来处理,找到表现比较好的parameters
以只带单个参数w的Loss Function L(w)为例,首先保证是可微的
我们的目标就是找到这个使Loss最小的,实际上就是寻找切线L斜率为0的global minima最小值点(注意,存在一些local minima极小值点,其斜率也是0)
有一个暴力的方法是,穷举所有的w值,去找到使loss最小的,但是这样做是没有效率的;而gradient descent就是用来解决这个效率问题的
首先随机选取一个初始的点 (当然也不一定要随机选取,如果有办法可以得到比较接近的表现得比较好的当初始点,可以有效地提高查找的效率)
计算在的位置的微分,即,几何意义就是切线的斜率
如果切线斜率是negative负的,那么就应该使w变大,即往右踏一步;如果切线斜率是positive正的,那么就应该使w变小,即往左踏一步,每一步的步长step size就是w的改变量
w的改变量step size的大小取决于两件事
一是现在的微分值有多大,微分值越大代表现在在一个越陡峭的地方,那它要移动的距离就越大,反之就越小;
二是一个常数项,被称为learning rate,即学习率,它决定了每次踏出的step size不只取决于现在的斜率,还取决于一个事先就定好的数值,如果learning rate比较大,那每踏出一步的时候,参数w更新的幅度就比较大,反之参数更新的幅度就比较小
如果learning rate设置的大一些,那机器学习的速度就会比较快;但是learning rate如果太大,可能就会跳过最合适的global minima的点
因此每次参数更新的大小是 ,为了满足斜率为负时w变大,斜率为正时w变小,应当使原来的w减去更新的数值,即
此时对应的斜率为0,我们找到了一个极小值local minima,这就出现了一个问题,当微分为0的时候,参数就会一直卡在这个点上没有办法再更新了,因此通过gradient descent找出来的solution其实并不是最佳解global minima
但幸运的是,在linear regression上,是没有local minima的,因此可以使用这个方法
今天要解决的关于宝可梦的问题,是含有two parameters的问题,即
当然,它本质上处理单个参数的问题是一样的
首先,也是随机选取两个初始值,和
然后分别计算这个点上,L对w和b的偏微分,即 和
更新参数,当迭代跳出时,对应着极小值点
实际上,L 的gradient就是微积分中的那个梯度的概念,即
每次计算得到的梯度gradient,即由组成的vector向量,就是该等高线的法线方向;而的作用就是让原先的朝着gradient的反方向即等高线法线方向前进,其中η(learning rate)的作用是每次更新的跨度(对应图中红色箭头的长度);经过多次迭代,最终gradient达到极小值点
注:这里两个方向的η(learning rate)必须保持一致,这样每次更新坐标的step size是等比例缩放的,保证坐标前进的方向始终和梯度下降的方向一致;否则坐标前进的方向将会发生偏移
gradient descent有一个令人担心的地方,它每次迭代完毕,寻找到的梯度为0的点必然是极小值点,local minima;却不一定是最小值点,global minima
这会造成一个问题,如果loss function长得比较坑坑洼洼(极小值点比较多),而每次初始化的取值又是随机的,这会造成每次gradient descent停下来的位置都可能是不同的极小值点;
而且当遇到梯度比较平缓(gradient≈0)的时候,gradient descent也可能会效率低下甚至可能会stuck卡住;
也就是说通过这个方法得到的结果,是看人品的
但是!在linear regression里,loss function实际上是convex的,是一个凸函数,是没有local optimal局部最优解的,他只有一个global minima,visualize出来的图像就是从里到外一圈一圈包围起来的椭圆形的等高线,因此随便选一个起始点,根据gradient descent最终找出来的,都会是同一组参数
随着的高次项的增加,对应的average error会不断地减小;实际上这件事情非常容易解释,实际上低次的式子是高次的式子的特殊情况(令高次项对应的为0,高次式就转化成低次式)
也就是说,在gradient descent可以找到best function的前提下(多次式为Non-linear model,存在local optimal局部最优解,gradient descent不一定能找到global minima),function所包含的项的次数越高,越复杂,error在training data上的表现就会越来越小;但是,我们关心的不是model在training data上的error表现,而是model在testing data上的error表现,在training data上,model越复杂,error就会越低;但是在testing data上,model复杂到一定程度之后,error非但不会减小,反而会暴增,在该例中,从含有项的model开始往后的model,testing data上的error出现了大幅增长的现象,通常被称为overfitting过拟合
原来的loss function只考虑了prediction的error,即;而regularization则是在原来的loss function的基础上加上了一项,就是把这个model里面所有的的平方和用λ加权。
也就是说,我们期待参数越小甚至接近于0的function,为什么呢?
因为参数值接近0的function,是比较平滑的;所谓的平滑的意思是,当今天的输入有变化的时候,output对输入的变化是比较不敏感的
举例来说,对这个model,当input变化,output的变化就是,也就是说,如果越小越接近0的话,输出对输入就越不sensitive敏感,我们的function就是一个越平滑的function;说到这里你会发现,我们之前没有把bias——b这个参数考虑进去的原因是bias的大小跟function的平滑程度是没有关系的,bias值的大小只是把function上下移动而已
如果我们有一个比较平滑的function,由于输出对输入是不敏感的,测试的时候,一些noises噪声对这个平滑的function的影响就会比较小,而给我们一个比较好的结果
注:这里的λ需要我们手动去调整以取得最好的值
λ值越大代表考虑smooth的那个regularization那一项的影响力越大,我们找到的function就越平滑
当我们的λ越大的时候,在training data上得到的error其实是越大的,但是这件事情是非常合理的,因为当λ越大的时候,我们就越倾向于考虑w的值而越少考虑error的大小;但是有趣的是,虽然在training data上得到的error越大,但是在testing data上得到的error可能会是比较小的;当然λ太大的时候,在testing data上的error就会越来越大
我们喜欢比较平滑的function,因为它对noise不那么sensitive;但是我们又不喜欢太平滑的function,因为它就失去了对data拟合的能力;而function的平滑程度,就需要通过调整λ来决定
根据已有的data特点(labeled data,包含宝可梦及进化后的cp值),确定使用supervised learning监督学习
根据output的特点(输出的是scalar数值),确定使用regression回归(linear or non-linear)
考虑包括进化前cp值、species、hp等各方面变量属性以及高次项的影响,我们的model可以采用这些input的一次项和二次型之和的形式,如:
而为了保证function的平滑性,loss function应使用regularization,即,注意bias——参数b对function平滑性无影响,因此不额外再次计入loss function(y的表达式里已包含w、b)
利用gradient descent对regularization版本的loss function进行梯度下降迭代处理,每次迭代都减去L对该参数的微分与learning rate之积,假设所有参数合成一个vector:,那么每次梯度下降的表达式如下:
当梯度稳定不变时,即为0时,gradient descent便停止,此时如果采用的model是linear的,那么vector必然落于global minima处(凸函数);如果采用的model是Non-linear的,vector可能会落于local minima处(此时需要采取其他办法获取最佳的function)
假定我们已经通过各种方法到达了global minima的地方,此时的vector:所确定的那个唯一的function就是在该λ下的最佳,即loss最小
这里λ的最佳数值是需要通过我们不断调整来获取的,因此令λ等于0,10,100,1000,...不断使用gradient descent或其他算法得到最佳的parameters:,并计算出这组参数确定的function——对training data和testing data上的error值,直到找到那个使testing data的error最小的λ,(这里一开始λ=0,就是没有使用regularization时的loss function)
表示那个真正的function,而表示这个的估测值estimator
就好像在打靶,是靶的中心点,收集到一些data做training以后,你会得到一个你觉得最好的function即,这个落在靶上的某个位置,它跟靶中心有一段距离,这段距离就是由Bias和variance决定的
bias:偏差;variance:方差
实际上对应着物理实验中系统误差和随机误差的概念,假设有n组数据,每一组数据都会产生一个相应的,此时bias表示所有的平均落靶位置和真值靶心的距离,variance表示这些的集中程度
假设独立变量为x(这里的x代表每次独立地从不同的training data里训练找到的),那么
总体期望 ;总体方差
由于我们只有有限组样本 ,故
样本均值 ;样本均值的期望 ; 样本均值的方差
样本均值 的期望是总体期望,也就是说是按概率对称地分布在总体期望的两侧的;而分布的密集程度取决于N,即数据量的大小,如果N比较大,就会比较集中,如果N比较小,就会以为中心分散开来
综上,样本均值以总体期望为中心对称分布,可以用来估测总体期望
由于我们只有有限组样本 ,故
样本均值 ;样本方差 ;样本方差的期望 ; 样本方差的方差
样本方差的期望是总体方差,而分布的密集程度也取决于N
同理,样本方差以总体方差为中心对称分布,可以用来估测总体方差
现在我们要估测的是靶的中心,每次collect data训练出来的是打在靶上的某个点;产生的error取决于:
的variance是由model决定的,一个简单的model在不同的training data下可以获得比较稳定分布的,而复杂的model在不同的training data下的分布比较杂乱(如果data足够多,那复杂的model也可以得到比较稳定的分布)
如果采用比较简单的model,那么每次在不同data下的实验所得到的不同的之间的variance是比较小的,就好像说,你在射击的时候,每次击中的位置是差不多的,就如同下图中的linear model,100次实验找出来的都是差不多的
但是如果model比较复杂,那么每次在不同data下的实验所得到的不同的之间的variance是比较大的,它的散布就会比较开,就如同下图中含有高次项的model,每一条都长得不太像,并且散布得很开
那为什么比较复杂的model,它的散布就比较开呢?比较简单的model,它的散布就比较密集呢?
原因其实很简单,其实前面在讲regularization正规化的时候也提到了部分原因。简单的model实际上就是没有高次项的model,或者高次项的系数非常小的model,这样的model表现得相当平滑,受到不同的data的影响是比较小的
举一个很极端的例子,我们的整个model(function set)里面,就一个function:f=c,这个function只有一个常数项,因此无论training data怎么变化,从这个最简单的model里找出来的都是一样的,它的variance就是等于0
bias是说,我们把所有的平均起来得到,这个与真值有多接近
当然这里会有一个问题是说,总体的真值我们根本就没有办法知道,因此这里只是假定了一个
当model比较简单的时候,每次实验得到的之间的variance会比较小,这些会稳定在一个范围内,但是它们的平均值距离真实值会有比较大的偏差;而当model比较复杂的时候,每次实验得到的之间的variance会比较大,实际体现出来就是每次重新实验得到的都会与之前得到的有较大差距,但是这些差距较大的的平均值却和真实值比较接近
也就是说,复杂的model,单次实验的结果是没有太大参考价值的,但是如果把考虑多次实验的结果的平均值,也许会对最终的结果有帮助
注:这里的单次实验指的是,用一组training data训练出model的一组有效参数以构成(每次独立实验使用的training data都是不同的)
实际上我们的model就是一个function set,当你定好一个model的时候,实际上就已经定好这个function set的范围了,那个最好的function只能从这个function set里面挑出来
如果是一个简单的model,它的function set的space是比较小的,这个范围可能根本就没有包含你的target;如果这个function set没有包含target,那么不管怎么sample,平均起来永远不可能是target(这里的space指上图中左下角那个被model圈起来的空间)
如果这个model比较复杂,那么这个model所代表的function set的space是比较大的(简单的model实际上就是复杂model的子集),那它就很有可能包含target,只是它没有办法找到那个target在哪,因为你给的training data不够,你给的training data每一次都不一样,所以他每一次找出来的都不一样,但是如果他们是散布在这个target附近的,那平均起来,实际上就可以得到和target比较接近的位置(这里的space指上图中右下角那个被model圈起来的空间)
由前面的讨论可知,比较简单的model,variance比较小,bias比较大;而比较复杂的model,bias比较小,variance比较大
可以发现,随着model的逐渐复杂:
这就是为什么我们之前要先计算出每一个model对应的error(每一个model都有唯一对应的,因此也有唯一对应的error),再挑选error最小的model的原因,只有这样才能综合考虑bias和variance的影响,找到一个实际error最小的model
当你自己在做research的时候,你必须要搞清楚,手头上的这个model,它目前主要的error是来源于哪里;你觉得你现在的问题是bias大,还是variance大
你应该先知道这件事情,你才能知道你的future work,你要improve你的model的时候,你应该要走哪一个方向
如果model没有办法fit training data的examples,代表bias比较大,这时是underfitting
形象地说,就是该model找到的上面并没有training data的大部分样本点,代表说这个model跟正确的model是有一段差距的,所以这个时候是bias大的情况,是underfitting
如果model可以fit training data,在training data上得到小的error,但是在testing data上,却得到一个大的error,代表variance比较大,这时是overfitting
遇到bias大或variance大的时候,你其实是要用不同的方式来处理它们
bias大代表,你现在这个model里面可能根本没有包含你的target,可能根本就不在你的function set里
对于error主要来自于bias的情况,是由于该model(function set)本来就不好,collect更多的data是没有用的,必须要从model本身出发
redesign,重新设计你的model
增加更多的features作为model的input输入变量
比如pokemon的例子里,只考虑进化前cp值可能不够,还要考虑hp值、species种类...作为model新的input变量
让model变得更复杂,增加高次项
比如原本只是linear model,现在考虑增加二次项、三次项...
增加data
如果是5次式,找100个,每次实验我们只用10只宝可梦的数据训练model,那我们找出来的100个的散布就会杂乱无章;但如果每次实验我们用100只宝可梦的数据训练model,那我们找出来的100个的分布就非常地集中
增加data是一个很有效控制variance的方法,假设你variance太大的话,collect data几乎是一个万能丹一样的东西,并且它不会伤害你的bias
但是它存在一个很大的问题是,实际上并没有办法去collect更多的data
如果没有办法collect更多的data,其实有一招,根据你对这个问题的理解,自己去generate更多“假的”data
Regularization(正规化)
我们现在会遇到的问题往往是这样:我们有很多个model可以选择,还有很多参数可以调,比如regularization的weight,那通常我们是在bias和variance之间做一些trade-off权衡
我们希望找一个model,它variance够小,bias也够小,这两个合起来给我们最小的testing data的error
你要做的事情是,把你的training set分成两组:
先在training set上找出每个model最好的function ,然后用validation set来选择你的model
也就是说,你手头上有3个model,你先把这3个model用training set训练出三个,接下来看一下它们在validation set上的performance
假设现在model3的performance最好,那你可以直接把这个model3的结果拿来apply在testing data上
如果你担心现在把training set分成training和validation两部分,感觉training data变少的话,可以这样做:已经从validation决定model3是最好的model,那就定住model3不变(function的表达式不变),然后用全部的data在model3上面再训练一次(使用全部的data去更新model3表达式的参数)
这个时候,如果你把这个训练好的model的apply到public testing set上面,虽然这么做,你得到的error表面上看起来是比较大的,但是这个时候你在public set上的error才能够真正反映你在private set上的error
当你得到public set上的error的时候(尽管它可能会很大),不建议回过头去重新调整model的参数,因为当你再回去重新调整什么东西的时候,你就又会把public testing set的bias给考虑进去了,这就又回到了第一种关系,即围绕着有偏差的testing data做model的优化
这样的话此时你在public set上看到的performance就没有办法反映实际在private set上的performance了,因为你的model是针对public set做过优化的,虽然public set上的error数据看起来可能会更好看,但是针对实际未知的private set,这个“优化”带来的可能是反作用,反而会使实际的error变大
因此这里只是说,你要keep in mind,如果在那个benchmark corpus上面所看到的testing的performance,它的error,肯定是大于它在real的application上应该有的值
比如说你现在常常会听到说,在image lab的那个corpus上面,error rate都降到3%,那个是超越人类了,但是真的是这样子吗?已经有这么多人玩过这个corpus,已经有这么多人告诉你说前面这些方法都不work,他们都帮你挑过model了,你已经用“testing” data调过参数了,所以如果你把那些model真的apply到现实生活中,它的error rate肯定是大于3%的
如果你不相信某一次分train和validation的结果的话,那你就分很多种不同的样子
比如说,如果你做3-flod的validation,意思就是你把training set分成三份,你每一次拿其中一份当做validation set,另外两份当training;分别在每个情境下都计算一下3个model的error,然后计算一下它的average error;然后你会发现在这三个情境下的average error,是model1最好
然后接下来,你就把用整个完整的training data重新训练一遍model1的参数;然后再去testing data上test
原则上是,如果你少去根据public testing set上的error调整model的话,那你在private testing set上面得到的error往往是比较接近public testing set上的error的
一般来说,error是bias和variance共同作用的结果
model比较简单和比较复杂的情况:
区分bias大 or variance大的情况
bias大 or variance大的情况下该如何处理
如何选择model
L : loss function
parameters(上标表示第几组参数,下标表示这组参数中的第几个参数)
Suppose that has two variables
Randomly start at
计算处的梯度:
在整个gradient descent的过程中,梯度不一定是递减的,但是沿着梯度下降的方向,函数值loss一定是递减的,且当gradient=0时,loss下降到了局部最小值,总结:梯度下降法指的是函数值loss随梯度下降的方向减小
初始随机在三维坐标系中选取一个点,这个三维坐标系的三个变量分别为,我们的目标是找到最小的那个loss也就是三维坐标系中高度最低的那个点,而gradient梯度(Loss等高线的法线方向)可以理解为高度上升最快的那个方向,它的反方向就是梯度下降最快的那个方向,于是每次update沿着梯度反方向,update的步长由梯度大小和learning rate共同决定,当某次update完成后,该点的gradient=0,说明到达了局部最小值
当参数有很多个的时候(>3),其实我们很难做到将loss随每个参数的变化可视化出来(因为最多只能可视化出三维的图像,也就只能可视化三维参数),但是我们可以把update的次数作为唯一的一个参数,将loss随着update的增加而变化的趋势给可视化出来
所以做gradient descent一个很重要的事情是,要把不同的learning rate下,loss随update次数的变化曲线给可视化出来,它可以提醒你该如何调整当前的learning rate的大小,直到出现稳定下降的曲线
显然这样手动地去调整learning rates很麻烦,因此我们需要有一些自动调整learning rates的方法
最基本、最简单的大原则是:learning rate通常是随着参数的update越来越小的
因为在起始点的时候,通常是离最低点是比较远的,这时候步伐就要跨大一点;而经过几次update以后,会比较靠近目标,这时候就应该减小learning rate,让它能够收敛在最低点的地方
举例:假设到了第t次update,此时
这种方法使所有参数以同样的方式同样的learning rate进行update,而最好的状况是每个参数都给他不同的learning rate去update
Divide the learning rate of each parameter by the root mean square(方均根) of its previous derivatives
Adagrad就是将不同参数的learning rate分开考虑的一种算法(adagrad算法update到后面速度会越来越慢,当然这只是adaptive算法中最简单的一种)
这里的w是function中的某个参数,t表示第t次update,表示Loss对w的偏微分,而是之前所有Loss对w偏微分的方均根(根号下的平方均值),这个值对每一个参数来说都是不一样的
由于和中都有一个的因子,两者相消,即可得到adagrad的最终表达式:
Adagrad的表达式里面有一件很矛盾的事情:
我们在做gradient descent的时候,希望的是当梯度值即微分值越大的时候(此时斜率越大,还没有接近最低点)更新的步伐要更大一些,但是Adagrad的表达式中,分母表示梯度越大步伐越小,分子却表示梯度越大步伐越大,两者似乎相互矛盾
在一些paper里是这样解释的:Adagrad要考虑的是,这个gradient有多surprise,即反差有多大,假设t=4的时候与前面的gradient反差特别大,那么与之间的大小反差就会比较大,它们的商就会把这一反差效果体现出来
同时,gradient越大,离最低点越远这件事情在有多个参数的情况下是不一定成立的
实际上,对于一个二次函数来说,最小值点的,而对于任意一点,它迈出最好的步伐长度是(这样就一步迈到最小值点了),联系该函数的一阶和二阶导数、,可以发现the best step is ,也就是说他不仅跟一阶导数(gradient)有关,还跟二阶导数有关
再来回顾Adagrad的表达式:
就是一次微分,而分母中的反映了二次微分的大小,所以Adagrad想要做的事情就是,在不增加任何额外运算的前提下,想办法去估测二次微分的值
随机梯度下降的方法可以让训练更快速,传统的gradient descent的思路是看完所有的样本点之后再构建loss function,然后去update参数;而stochastic gradient descent的做法是,看到一个样本点就update一次,因此它的loss function不是所有样本点的error平方和,而是这个随机样本点的error平方
这里有一个秘密,就是我们在做deep learning的gradient descent的时候,并不会真的去minimize total loss,那我们做的是什么呢?我们会把Training data分成一个一个的batch,比如说你的Training data一共有1w张image,每次random选100张image作为一个batch(我的理解是,先将原来的image分布随机打乱,然后再按顺序每次挑出batch_size张image组成一个batch,这样才能保证所有的data都有被用到,且不同的batch里不会出现重复的data)
像gradient descent一样,先随机initialize network的参数
选第一个batch出来,然后计算这个batch里面的所有element的total loss,,接下来根据去update参数,也就是计算对所有参数的偏微分,然后update参数
注意:不是全部data的total loss
再选择第二个batch,现在这个batch的total loss是,接下来计算对所有参数的偏微分,然后update参数
反复做这个process,直到把所有的batch通通选过一次,所以假设你有100个batch的话,你就把这个参数update 100次,把所有batch看过一次,就叫做一个epoch
重复epoch的过程,所以你在train network的时候,你会需要好几十个epoch,而不是只有一个epoch
整个训练的过程类似于stochastic gradient descent,不是将所有数据读完才开始做gradient descent的,而是拿到一部分数据就做一次gradient descent
前面已经提到了,stochastic gradient descent速度快,表现好,既然如此,为什么我们还要用Mini-batch呢?这就涉及到了一些实际操作上的问题,让我们必须去用Mini-batch
举例来说,我们现在有50000个examples,如果我们把batch size设置为1,就是stochastic gradient descent,那在一个epoch里面,就会update 50000次参数;如果我们把batch size设置为10,在一个epoch里面,就会update 5000次参数
看上去stochastic gradient descent的速度貌似是比较快的,它一个epoch更新参数的次数比batch size等于10的情况下要快了10倍,但是!我们好像忽略了一个问题,我们之前一直都是下意识地认为不同batch size的情况下运行一个epoch的时间应该是相等的,然后我们才去比较每个epoch所能够update参数的次数,可是它们又怎么可能会是相等的呢?
实际上,当你batch size设置不一样的时候,一个epoch需要的时间是不一样的,以GTX 980为例,下图是对总数为50000笔的Training data设置不同的batch size时,每一个epoch所需要花费的时间
也就是说,当stochastic gradient descent算了一个epoch的时候,batch size为10的情况已经算了近10个epoch了;所以case1跑一个epoch,做了50000次update参数的同时,case2跑了十个epoch,做了近5000*10=50000次update参数;你会发现batch size设1和设10,update参数的次数几乎是一样的
如果不同batch size的情况,update参数的次数几乎是一样的,你其实会想要选batch size更大的情况,就像在本例中,相较于batch size=1,你会更倾向于选batch size=10,因为batch size=10的时候,是会比较稳定的,因为由更大的数据集计算的梯度能够更好的代表样本总体,从而更准确的朝向极值所在的方向
我们之前把gradient descent换成stochastic gradient descent,是因为后者速度比较快,update次数比较多,可是现在如果你用stochastic gradient descent并没有见得有多快,那你为什么不选一个update次数差不多,又比较稳定的方法呢?
上面例子的现象产生的原因是我们用了GPU,用了平行运算,所以batch size=10的时候,这10个example其实是同时运算的,所以你在一个batch里算10个example的时间跟算1个example的时间几乎可以是一样的
那你可能会问,既然batch size越大,它会越稳定,而且还可以平行运算,那为什么不把batch size变得超级大呢?这里有两个claim(声明):
第一个claim就是,如果你把batch size开到很大,最终GPU会没有办法进行平行运算,它终究是有自己的极限的,也就是说它同时考虑10个example和1个example的时间是一样的,但当它考虑10000个example的时候,时间就不可能还是跟一个example一样,因为batch size考虑到硬件限制,是没有办法无穷尽地增长的
第二个claim是说,如果把batch size设的很大,在train gradient descent的时候,可能跑两下你的network就卡住了,就陷到saddle point或者local minima里面去了
因为在neural network的error surface上面,如果你把loss的图像可视化出来的话,它并不是一个convex的optimization problem,不会像理想中那么平滑,实际上它会有很多的坑坑洞洞
如果你用的batch size很大,甚至是Full batch,那你走过的路径会是比较平滑连续的,可能这一条平滑的曲线在走向最低点的过程中就会在坑洞或是缓坡上卡住了;但是,如果你的batch size没有那么大,意味着你走的路线没有那么的平滑,有些步伐走的是随机性的,路径是会有一些曲折和波动的
可能在你走的过程中,它的曲折和波动刚好使得你“绕过”了那些saddle point或是local minima的地方;或者当你陷入不是很深的local minima或者没有遇到特别麻烦的saddle point的时候,它步伐的随机性就可以帮你跳出这个gradient接近于0的区域,于是你更有可能真的走向global minima的地方
而对于Full batch的情况,它的路径是没有随机性的,是稳定朝着目标下降的,因此在这个时候去train neural network其实是有问题的,可能update两三次参数就会卡住,所以mini batch是有必要的
如下图,左边是full batch(拿全部的Training data做一个batch)的梯度下降效果,可以看到每一次迭代成本函数都呈现下降趋势,这是好的现象,说明我们w和b的设定一直再减少误差, 这样一直迭代下去我们就可以找到最优解;右边是mini batch的梯度下降效果,可以看到它是上下波动的,成本函数的值有时高有时低,但总体还是呈现下降的趋势, 这个也是正常的,因为我们每一次梯度下降都是在min batch上跑的而不是在整个数据集上, 数据的差异可能会导致这样的波动(可能某段数据效果特别好,某段数据效果不好),但没关系,因为它整体是呈下降趋势的

把下面的图看做是梯度下降空间:蓝色部分是full batch而紫色部分是mini batch,就像上面所说的mini batch不是每次迭代损失函数都会减少,所以看上去好像走了很多弯路,不过整体还是朝着最优解迭代的,而且由于mini batch一个epoch就走了5000步(5000次梯度下降),而full batch一个epoch只有一步,所以虽然mini batch走了弯路但还是会快很多
而且,就像之前提到的那样,mini batch在update的过程中,步伐具有随机性,因此紫色的路径可以在一定程度上绕过或跳出saddle point、local minima这些gradient趋近于0的地方;而蓝色的路径因为缺乏随机性,只能按照既定的方式朝着目标前进,很有可能就在中途被卡住,永远也跳不出来了

当然,就像之前讨论的一样,如果batch size太小,会造成速度不仅没有加快反而会导致下降的曲线更加不稳定的情况产生
因此batch size既不能太大,因为它会受到硬件GPU平行加速的限制,导致update次数过于缓慢,并且由于缺少随机性而很容易在梯度下降的过程中卡在saddle point或是local minima的地方(极端情况是Full batch);而且batch size也不能太小,因为它会导致速度优势不明显的情况下,梯度下降曲线过于不稳定,算法可能永远也不会收敛(极端情况是Stochastic gradient descent)
整个network,不管是Forward pass还是Backward pass,都可以看做是一连串的矩阵运算的结果
那今天我们就可以比较batch size等于1(stochastic gradient descent)和10(mini batch)的差别
如下图所示,stochastic gradient descent就是对每一个input x进行单独运算;而mini batch,则是把同一个batch里面的input全部集合起来,假设现在我们的batch size是2,那mini batch每一次运算的input就是把黄色的vector和绿色的vector拼接起来变成一个matrix,再把这个matrix乘上,你就可以直接得到和
这两件事在理论上运算量是一样多的,但是在实际操作上,对GPU来说,在矩阵里面相乘的每一个element都是可以平行运算的,所以图中stochastic gradient descent运算的时间反而会变成下面mini batch使用GPU运算速度的两倍,这就是为什么我们要使用mini batch的原因

所以,如果你买了GPU,但是没有使用mini batch的话,其实就不会有多少加速的效果
特征缩放,当多个特征的分布范围很不一样时,最好将这些不同feature的范围缩放成一样
,假设x1的值都是很小的,比如1,2...;x2的值都是很大的,比如100,200...
此时去画出loss的error surface,如果对w1和w2都做一个同样的变动,那么w1的变化对y的影响是比较小的,而w2的变化对y的影响是比较大的
对于error surface表示,w1对y的影响比较小,所以w1对loss是有比较小的偏微分的,因此在w1的方向上图像是比较平滑的;w2对y的影响比较大,所以w2对loss的影响比较大,因此在w2的方向上图像是比较sharp的
如果x1和x2的值,它们的scale是接近的,那么w1和w2对loss就会有差不多的影响力,loss的图像接近于圆形,那这样做对gradient descent有什么好处呢?
之前我们做的demo已经表明了,对于这种长椭圆形的error surface,如果不使用Adagrad之类的方法,是很难搞定它的,因为在像w1和w2这样不同的参数方向上,会需要不同的learning rate,用相同的lr很难达到最低点
如果有scale的话,loss在参数w1、w2平面上的投影就是一个正圆形,update参数会比较容易
而且gradient descent的每次update并不都是向着最低点走的,每次update的方向是顺着等高线的方向(梯度gradient下降的方向),而不是径直走向最低点;但是当经过对input的scale使loss的投影是一个正圆的话,不管在这个区域的哪一个点,它都会向着圆心走。因此feature scaling对参数update的效率是有帮助的
假设有R个example(上标i表示第i个样本点),,每一笔example,它里面都有一组feature(下标j表示该样本点的第j个特征)
对每一个demension i,都去算出它的平均值mean=,以及标准差standard deviation=
对第r个example的第i个component,减掉均值,除以标准差,即
实际上就是将每一个参数都归一化成标准正态分布,即,其中表示第i个参数
Given a point, we can easily find the point with the smallest value nearby. How?
泰勒表达式:
When x is close to :
同理,对于二元函数,when x and y is close to and :
对于loss图像上的某一个点(a,b),如果我们想要找这个点附近loss最小的点,就可以用泰勒展开的思想
假设用一个red circle限定点的范围,这个圆足够小以满足泰勒展开的精度,那么此时我们的loss function就可以化简为:
令,,
则
假定red circle的半径为d,则有限制条件:
此时去求,这里有个小技巧,把转化为两个向量的乘积:
当向量与向量反向,且刚好到达red circle的边缘时(用去控制向量的长度),最小
实际上就是,于是局部最小值对应的参数为中心点减去gradient的加权
这就是gradient descent在数学上的推导,注意它的重要前提是,给定的那个红色圈圈的范围要足够小,这样泰勒展开给我们的近似才会更精确,而的值是与圆的半径成正比的,因此理论上learning rate要无穷小才能够保证每次gradient descent在update参数之后的loss会越来越小,于是当learning rate没有设置好,泰勒近似不成立,就有可能使gradient descent过程中的loss没有越来越小
当然泰勒展开可以使用二阶、三阶乃至更高阶的展开,但这样会使得运算量大大增加,反而降低了运行效率
gradient descent的限制是,它在gradient即微分值接近于0的地方就会停下来,而这个地方不一定是global minima,它可能是local minima,可能是saddle point鞍点,甚至可能是一个loss很高的plateau平缓高原
分类问题是找一个function,它的input是一个object,它的输出是这个object属于哪一个class
要想把一个东西当做function的input,就需要把它数值化
Regression的output是一个real number,但是在classification的时候,它的output是discrete(用来表示某一个class)
我们要找的function f(x)里面会有另外一个function g(x),当我们的input x输入后,如果g(x)>0,那f(x)的输出就是class 1,如果g(x)<0,那f(x)的输出就是class 2,这个方法保证了function的output都是离散的表示class的数值
之前不是说输出是1,2,3...是不行的吗,注意,那是针对Regression的loss function而言的,因为Regression的loss function是用output与“真值”的平方和作为评判标准的,这样输出值(3,2)与(3,1)之间显然是(3,2)关系更密切一些,为了解决这个问题,我们只需要重新定义一个loss function即可
我们可以把loss function定义成,即这个model在所有的training data上predict预测错误的次数,也就是说分类错误的次数越少,这个function表现得就越好
但是这个loss function没有办法微分,无法用gradient descent的方法去解的,当然有Perceptron、SVM这些方法可以用,但这里先用另外一个solution来解决这个问题
假设我们考虑一个二元分类的问题,我们拿到一个input x,想要知道这个x属于class 1或class 2的概率
实际上就是一个贝叶斯公式,x属于class 1的概率就等于class 1自身发生的概率乘上在class 1里取出x这种颜色的球的概率除以在class 1和 class 2里取出x这种颜色的球的概率(后者是全概率公式)
贝叶斯公式=单条路径概率/所有路径概率和
因此我们想要知道x属于class 1或是class 2的概率,只需要知道4个值:,我们希望从Training data中估测出这四个值
这一整套想法叫做Generative model(生成模型),因为如果你可以计算出每一个x出现的概率,就可以用这个distribution分布来生成x、sample x出来
和这两个概率,被称为Prior,计算这两个值还是比较简单的
假设我们还是考虑二元分类问题,编号小于400的data用来Training,编号大于400的data用来testing,如果想要严谨一点,可以在Training data里面分一部分validation出来模拟testing的情况。
在Training data里面,有79只水系宝可梦,61只一般系宝可梦,那么,
现在的问题是,怎么得到和的值
这里表示均值,表示方差,那高斯函数的概率密度函数则是:
Input: vector x, output: probability of sampling x
The shape of the function determines by mean and covariance matrix
同样的,不同的,概率分布最高点的地方是不一样的;同理,如果是同样的,不同的,概率分布最高点的地方是一样的,但是分布的密集程度是不一样的。
那从这79个已有的点找出Gaussian,只需要去估测出这个Gaussian的均值和协方差即可
估测和的方法就是极大似然估计法(Maximum Likelihood),极大似然估计的思想是,找出最特殊的那对和,从它们共同决定的高斯函数中再次采样出79个点,使”得到的分布情况与当前已知79点的分布情况相同“这件事情发生的可能性最大
极大似然函数,实际上就是该事件发生的概率就等于每个点都发生的概率之积,我们只需要把每一个点的data代进去,就可以得到一个关于和的函数,分别求偏导,解出微分是0的点,即 使L最大的那组参数,便是最终的估测值,通过微分得到的高斯函数和的最优解如下:
当然如果你不愿意去求微分的话,这也可以当做公式来记忆(刚好是数学期望,刚好是协方差)
数学期望:,协方差:,对同一个变量来说,协方差为
根据,只要带入某一个input x,就可以通过这个式子计算出它属于class 1的机率
其实之前使用的model是不常见的,你是不会经常看到给每一个Gaussian都有自己的mean和covariance,比如我们的class 1用的是和,class 2用的是和,比较常见的做法是,不同的class可以share同一个cocovariance matrix
其实variance是跟input的feature size的平方成正比的,所以当feature的数量很大的时候,大小的增长是可以非常快的,在这种情况下,给不同的Gaussian以不同的covariance matrix,会造成model的参数太多,而参数多会导致该model的variance过大,出现overfitting的现象,因此对不同的class使用同一个covariance matrix,可以有效减少参数
此时就把、和共同的一起去合成一个极大似然函数,此时可以发现,得到的和和原来一样,还是各自的均值,而则是原先两个和的加权
再来看一下结果,class 1和class 2在没有共用covariance matrix之前,它们的分界线是一条曲线;如果共用covariance matrix的话,它们之间的分界线就会变成一条直线,这样的model,我们也称之为linear model(尽管Gaussian不是linear的,但是它分两个class的boundary是linear)
如果我们考虑所有的feature,并共用covariance的话,原来的54%的正确率就会变成73%。但是为什么会做到这样子,我们是很难分析的,因为这是在高维空间中发生的事情,我们很难知道boundary到底是怎么切的,但这就是machine learning它fancy的地方,人没有办法知道怎么做,但是machine可以帮我们做出来
Find a function set(model)
prior probability 和probability distribution 就是model的参数
当posterior Probability 的话,就output class 1,反之就output class 2
Goodness of function
对于Gaussian distribution这个model来说,我们要评价的是决定这个高斯函数形状的均值和协方差这两个参数的好坏,而极大似然函数的输出值,就评价了这组参数的好坏
Find the best function
找到的那个最好的function,就是使值最大的那组参数,实际上就是所有样本点的均值和协方差
这里上标i表示第i个点,这里x是一个features的vector,用下标来表示这个vector中的某个feature
你可以选择自己喜欢的Probability distribution概率分布函数,如果你选择的是简单的分布函数(参数比较少),那你的bias就大,variance就小;如果你选择复杂的分布函数,那你的bias就小,variance就大,那你就可以用data set来判断一下,用什么样的Probability distribution作为model是比较好的
我们可以考虑这样一件事情,假设中每一个dimension 的分布都是相互独立的,它们之间的covariance都是0,那我们就可以把x产生的机率拆解成产生的机率之积
这里每一个dimension的分布函数都是一维的Gaussian distribution,如果这样假设的话,等于是说,原来那多维度的Gaussian,它的covariance matrix变成是diagonal(对角的),在不是对角线的地方,值都是0,这样就可以更加减少需要的参数量,就可以得到一个更简单的model
我们把上述这种方法叫做Naive Bayes Classifier(朴素贝叶斯分类法),如果真的明确了所有的feature之间是相互独立的,是不相关的,使用朴素贝叶斯分类法的performance是会很好的,如果这个假设是不成立的,那么Naive bayes classfier的bias就会很大,它就不是一个好的classifier(朴素贝叶斯分类法本质就是减少参数)
总之,寻找model总的原则是,尽量减少不必要的参数,但是必然的参数绝对不能少
那怎么去选择分布函数呢?有很多时候凭直觉就可以看出来,比如某个feature是binary的,它代表的是:是或不是,这个时候就不太可能是高斯分布了,而很有可能是Bernoulli distributions
接下来我们来分析一下这个表达式,会发现一些有趣的现象
表达式上下同除以分子,令,得到,这个function叫做sigmoid function

其中,Sigmoid函数是已知函数,因此我们来推导一下z的具体形式
(当和共用一个时,经过化简相消z就变成了一个linear的function,x的系数是一个vector w,后面的一大串数字其实就是一个常数项b)

这个式子就解释了,当class 1和class 2共用的时候,它们之间的boundary会是linear的
在Generative model里面,我们做的事情是,我们用某些方法去找出,找出这些后算出w和b,把它们代进,就可以算概率,但是,当你看到这个式子的时候,你可能会有一个直觉的想法,为什么要这么麻烦呢?我们的最终目标都是要找一个vector w和constant b,我们何必先去搞个概率,算出一些什么的,然后再回过头来又去算w和b,这不是舍近求远吗?
所以我们能不能直接把w和b找出来呢?
在Classification这一章节,我们讨论了如何通过样本点的均值和协方差来计算,进而利用计算得到新的样本点x属于class 1的概率,由于是二元分类,属于class 2的概率。
可知,。
之后我们推导了在Gaussian distribution下考虑class 1和class 2共用,可以得到一个线性的z(很多其他的Probability model经过化简以后也都可以得到同样的结果)
这里的w和x都是vector,两者的乘积是inner product,从上式中我们可以看出,现在这个model(function set)是受w和b控制的,因此我们不必要再去像前面一样计算一大堆东西,而是用这个全新的由w和b决定的model——Logistic Regression(逻辑回归)
因此Function Set为:
:weight,:bias,:sigmoid function,:input

现在我们有N笔Training data,每一笔data都要标注它是属于哪一个class
假设这些Training data是从我们定义的posterior Probability中产生的,而w和b就决定了这个posterior Probability,那我们就可以去计算某一组w和b去产生这N笔Training data的概率,利用极大似然估计的思想,最好的那组参数就是有最大可能性产生当前N笔Training data分布的和
似然函数只需要将每一个点产生的概率相乘即可,注意,这里假定是二元分类,class 2的概率为1减去class 1的概率
由于是乘积项的形式,为了方便计算,我们将上式做个变换:
为了统一格式,这里将Logistic Regression里的所有Training data都打上0和1的标签,即output 代表class 1,output 代表class 2,于是上式进一步改写成:
现在已经有了统一的格式,我们就可以把要minimize的对象写成一个summation的形式:
这里表示第n个样本点,表示第n个样本点的class标签(1表示class 1,0表示class 2),最终这个summation的形式,里面其实是两个Bernouli distribution的cross entropy
假设有如上两个distribution p和q,它们的交叉熵就是
cross entropy交叉熵的含义是表达这两个distribution有多接近,如果p和q这两个distribution一模一样的话,那它们算出来的cross entropy就是0,而这里表示function的output,表示预期的target,因此交叉熵实际上表达的是希望这个function的output和它的target越接近越好
总之,我们要找的参数实际上就是:
实际上就是去找到使loss function即交叉熵之和最小的那组参数就行了,这里用gradient descent的方法进行运算就ok
sigmoid function的微分:

先计算对的偏微分,这里和是常数先不用管它,只需要分别求出和对的偏微分即可,整体推导过程如下:

将得到的式子进行进一步化简,可得:

我们发现最终的结果竟然异常的简洁,gradient descent每次update只需要做:
那这个式子到底代表着什么意思呢?现在你的update取决于三件事:
我们可以把逻辑回归和之前将的线性回归做一个比较
Logistic Regression是把每一个feature 加权求和,加上bias,再通过sigmoid function,当做function的output
因为Logistic Regression的output是通过sigmoid function产生的,因此一定是介于0~1之间;而linear Regression的output并没有通过sigmoid function,所以它可以是任何值
在Logistic Regression中,我们定义的loss function,即要去minimize的对象,是所有example(样本点)的output( )和实际target( )在Bernoulli distribution(两点分布)下的cross entropy(交叉熵)总和
而在linear Regression中,loss function的定义相对比较简单,就是单纯的function的output( )和实际target( )在数值上的平方和的均值
这里可能会有一个疑惑,为什么Logistic Regression的loss function不能像linear Regression一样用square error来表示呢?后面会有进一步的解释
神奇的是,Logistic Regression和Linear Regression的update的方式是一模一样的

之前提到了,为什么Logistic Regression的loss function不能用square error来描述呢?

现在会遇到一个问题:
如果第n个点的目标target是class 1,,此时如果function的output 的话,得到的微分为0;但是当function的output 的时候,微分也是0
如果举class 2的例子,得到的结果与class 1是一样的
如果我们把参数的变化对total loss作图的话,loss function选择cross entropy或square error,参数的变化跟loss的变化情况可视化出来如下所示:

假设中心点就是距离目标很近的地方,如果是cross entropy的话,距离目标越远,微分值就越大,参数update的时候变化量就越大,迈出去的步伐也就越大
但当你选择square error的时候,过程就会很卡,因为距离目标远的时候,微分也是非常小的,移动的速度是非常慢的,我们之前提到过,实际操作的时候,当gradient接近于0的时候,其实就很有可能会停下来,因此使用square error很有可能在一开始的时候就卡住不动了,而且这里也不能随意地增大learning rate,因为在做gradient descent的时候,你的gradient接近于0,有可能离target很近也有可能很远,因此不知道learning rate应该设大还是设小
综上,尽管square error可以使用,但是会出现update十分缓慢的现象,而使用cross entropy可以让你的Training更顺利
Logistic Regression的方法,我们把它称之为discriminative的方法;而我们用Gaussian来描述posterior Probability这件事,我们称之为Generative的方法
实际上它们用的model(function set)是一模一样的,都是,如果是用Logistic Regression的话,可以用gradient descent的方法直接去把b和w找出来;如果是用Generative model的话,我们要先去算,然后算出b和w
你会发现用这两种方法得到的b和w是不同的,尽管我们的function set是同一个,但是由于做了不同的假设,最终从同样的Training data里找出来的参数会是不一样的
在Logistic Regression里面,我们没有做任何实质性的假设,没有对Probability distribution有任何的描述,我们就是单纯地去找b和w
而在Generative model里面,我们对Probability distribution是有实质性的假设的,之前我们假设的是Gaussian(高斯分布),甚至假设在相互独立的前提下是否可以是naive bayes(朴素贝叶斯),根据这些假设我们才找到最终的b和w
哪一个假设的结果是比较好的呢?实际上Discriminative的方法常常会比Generative的方法表现得更好,这里举一个简单的例子来解释一下
假设总共有两个class,有这样的Training data:每一笔data有两个feature,总共有1+4+4+4=13笔data
如果我们的testing data的两个feature都是1,凭直觉来说会认为它肯定是class 1,但是如果用naive bayes的方法(朴素贝叶斯假设所有的feature相互独立,方便计算),得到的结果又是怎样的呢?

通过Naive bayes得到的结果竟然是这个测试点属于class 2的可能性更大,这跟我们的直觉比起来是相反的,实际上我们直觉认为两个feature都是1的测试点属于class 1的可能性更大是因为我们潜意识里认为这两个feature之间是存在某种联系的,但是对Naive bayes来说,它是不考虑不同dimension之间的correlation,Naive bayes认为在dimension相互独立的前提下,class 2没有sample出都是1的data,是因为sample的数量不够多,如果sample够多,它认为class 2观察到都是1的data的可能性会比class 1要大
Naive bayes认为从class 2中找到样本点x的概率是x中第一个feature出现的概率与第二个feature出现的概率之积:;但是我们的直觉告诉自己,两个feature之间肯定是有某种联系的,不能够那么轻易地被拆分成两个独立的概率乘积,也就是说Naive bayes自作聪明地多假设了一些条件
所以,Generative model和discriminative model的差别就在于,Generative的model它有做了某些假设,假设你的data来自于某个概率模型;而Discriminative的model是完全不作任何假设的
通常脑补不是一件好的事情,因为你给你的data强加了一些它并没有告诉你的属性,但是在data很少的情况下,脑补也是有用的,discriminative model并不是在所有的情况下都可以赢过Generative model,discriminative model是十分依赖于data的,当data数量不足或是data本身的label就有一些问题,那Generative model做一些脑补和假设,反而可以把data的不足或是有问题部分的影响给降到最低
在Generative model中,priors probabilities和class-dependent probabilities是可以拆开来考虑的,以语音辨识为例,现在用的都是neural network,是一个discriminative的方法,但事实上整个语音辨识的系统是一个Generative的system,它的prior probability是某一句话被说出来的机率,而想要estimate某一句话被说出来的机率并不需要有声音的data,去互联网上爬取大量文字就可以计算出某一段文字出现的机率,并不需要声音的data,这个就是language model,而class-dependent的部分才需要声音和文字的配合,这样的处理可以把prior预测地更精确
对于分类的问题(主要是二元分类),我们一般有两种方法去处理问题,一种是Generative的方法,另一种是Discriminative的方法,注意到分类问题的model都是从贝叶斯方程出发的,即
其中分子表示属于第i类的可能性,分母表示遍历从1到n所有的类的可能性,两种方法的区别在于:
Generative model会假设一个带参数的Probability contribute,利用这个假设的概率分布函数带入(1)中去计算和,结合极大似然估计法最终得到最优的参数以确定这个model的具体形式
DIscriminative model不作任何假设,因此它无法通过假定的Probability distribution得到的表达式,因此它使用的是(2),直接去利用交叉熵和gradient descent结合极大似然估计法得到最优的b和w,以确定model的具体形式
最后,利用得到的与0.5相比较来判断它属于那个class的可能性更大
Generative model的好处是,它对data的依赖并没有像discriminative model那么严重,在data数量少或者data本身就存在noise的情况下受到的影响会更小,而它还可以做到Prior部分与class-dependent部分分开处理,如果可以借助其他方式提高Prior model的准确率,对整一个model是有所帮助的(比如前面提到的语音辨识)
而Discriminative model的好处是,在data充足的情况下,它训练出来的model的准确率一般是比Generative model要来的高的
之前讲的都是二元分类的情况,这里讨论一下多元分类问题,其原理的推导过程与二元分类基本一致
假设有三个class:,每一个class都有自己的weight和bias,这里分布代表三个vector,分别代表三个const,input x也是一个vector
softmax的意思是对最大值做强化,因为在做第一步的时候,对取exponential会使大的值和小的值之间的差距被拉得更开,也就是强化大的值
我们把丢进一个softmax的function,softmax做的事情是这样三步:
原来的output z可以是任何值,但是做完softmax之后,你的output 的值一定是介于0~1之间,并且它们的和一定是1,,以上图为例,表示input x属于第i个class的概率,比如属于C1的概率是,属于C2的概率是,属于C3的概率是
而softmax的output,就是拿来当z的posterior probability
假设我们用的是Gaussian distribution(共用covariance),经过一般推导以后可以得到softmax的function。同样从information theory也可以推导出softmax function,Maximum entropy本质内容和Logistic Regression是一样的,它是从另一个观点来切入为什么我们的classifier长这样子
如下图所示,input x经过三个式子分别生成,经过softmax转化成output ,它们分别是这三个class的posterior probability,由于summation=1,因此做完softmax之后就可以把y的分布当做是一个probability contribution,我们在训练的时候还需要有一个target,因为是三个class,output是三维的,对应的target也是三维的,为了满足交叉熵的条件,target 也必须是probability distribution,这里我们不能使用1,2,3作为class的区分,为了保证所有class之间的关系是一样的,这里使用类似于one-hot编码的方式,即

这个时候就可以计算output 和 target 之间的交叉熵,即,同二元分类一样,多元分类问题也是通过极大似然估计法得到最终的交叉熵表达式的,这里不再赘述
Logistic Regression其实有很强的限制,给出下图的例子中的Training data,想要用Logistic Regression对它进行分类,其实是做不到的

因为Logistic Regression在两个class之间的boundary就是一条直线,但是在这个平面上无论怎么画直线都不可能把图中的两个class分隔开来
如果坚持要用Logistic Regression的话,有一招叫做Feature Transformation,原来的feature分布不好划分,那我们可以将之转化以后,找一个比较好的feature space,让Logistic Regression能够处理
假设这里定义是原来的点到之间的距离,是原来的点到之间的距离,重新映射之后如下图右侧(红色两个点重合),此时Logistic Regression就可以把它们划分开来

但麻烦的是,我们并不知道怎么做feature Transformation,如果在这上面花费太多的时间就得不偿失了,于是我们会希望这个Transformation是机器自己产生的,怎么让机器自己产生呢?我们可以让很多Logistic Regression cascade(连接)起来
我们让一个input x的两个feature 经过两个Logistic Regression的transform,得到新的feature ,在这个新的feature space上,class 1和class 2是可以用一条直线分开的,那么最后只要再接另外一个Logistic Regression的model(对它来说,才是每一个样本点的"feature",而不是原先的),它根据新的feature,就可以把class 1和class 2分开

因此着整个流程是,先用n个Logistic Regression做Feature Transformation(n为每个样本点的feature数量),生成n个新的feature,然后再用一个Logistic Regression作classifier
Logistic Regression的boundary一定是一条直线,具体的分布是由Logistic Regression的参数决定的,直线是由决定的(二维feature的直线画在二维平面上,多维feature的直线则是画在多维空间上)
下图是二维feature的例子,分别表示四个点经过transform之后的和,在新的feature space中可以通过最后的Logistic Regression划分开来

注意,这里的Logistic Regression只是一条直线,它指的是“属于这个类”或“不属于这个类”这两种情况,因此最后的这个Logistic Regression是跟要检测的目标类相关的,当只是二元分类的时候,最后只需要一个Logistic Regression即可,当面对多元分类问题,需要用到多个Logistic Regression来画出多条直线划分所有的类,每一个Logistic Regression对应它要检测的那个类
通过上面的例子,我们发现,多个Logistic Regression连接起来会产生powerful的效果,我们把每一个Logistic Regression叫做一个neuron(神经元),把这些Logistic Regression串起来所形成的network,就叫做Neural Network,就是类神经网路,这个东西就是Deep Learning。

1958:Perceptron(linear model),感知机的提出
1969:Perceptron has limitation,from MIT
1980s:Multi-layer Perceptron,多层感知机
1986:Backpropagation,反向传播
1989: 1 hidden layer is “good enough”,why deep?
2006:RBM initialization(breakthrough):Restricted Boltzmann Machine,受限玻尔兹曼机
2009:GPU加速的发现
2011:start to be popular in speech recognition,语音识别领域
2012:win ILSVRC image competition,Deep learning开始在图像领域流行
实际上,Deep learning跟machine learning一样,也是“大象放进冰箱”三个步骤:Step 1: define a set of function,Step 2: goodness of function,Step 3: pick the best function
把多个Logistic Regression前后connect在一起,然后把一个Logistic Regression称之为neuron,整个称之为neural network
我们可以用不同的方法连接这些neuron,就可以得到不同的structure,neural network里的每一个Logistic Regression都有自己的weight和bias,这些weight和bias集合起来,就是这个network的parameter,我们用来描述
那该怎么把它们连接起来呢?这是需要你手动去设计的,最常见的连接方式叫做Fully Connect Feedforward Network(全连接前馈网络)
如果一个neural network里面的参数weight和bias已知的话,它就是一个function,它的input是一个vector,output是另一个vector,这个vector里面放的是样本点的feature,vector的dimension就是feature的个数
如果我们还不知道参数,只是定出了这个network的structure,只是决定好这些neuron该怎么连接在一起,这样的一个network structure其实是define了一个function set(model),我们给这个network设不同的参数,它就变成了不同的function,把这些可能的function集合起来,就是function set
只不过我们用neural network决定function set的时候,这个function set是比较大的,它包含了很多Logistic Regression、linear Regression没有办法包含的function
下图中,每一排表示一个layer,每个layer里面的每一个球都代表一个neuron。因为layer和layer之间,所有的neuron都是两两连接,所以它叫Fully connected的network;因为现在传递的方向是从layer 1->2->3,由后往前传,所以它叫做Feedforward network
layer和layer之间neuron是两两互相连接的,layer 1的neuron output会连接给layer 2的每一个neuron作为input
对整个neural network来说,它需要一个input,这个input就是一个feature的vector,而对layer 1的每一个neuron来说,它的input就是input layer的每一个dimension
最后那个layer L,由于它后面没有接其它东西了,所以它的output就是整个network的output
这里每一个layer都是有名字的
每一个neuron里面的sigmoid function,在Deep Learning中被称为activation function(激励函数),事实上它不见得一定是sigmoid function,还可以是其他function(sigmoid function是从Logistic Regression迁移过来的,现在已经较少在Deep learning里使用了)
有很多层layers的neural network,被称为DNN(Deep Neural Network)

那所谓的deep,是什么意思呢?有很多层hidden layer,就叫做deep,具体的层数并没有规定,现在只要是neural network base的方法,都被称为Deep Learning。
使用了152个hidden layers的Residual Net,不是使用一般的Fully Connected Feedforward Network,它需要设计特殊的special structure才能训练这么深的network
network的运作过程,我们通常会用Matrix Operation来表示,以下图为例,假设第一层hidden layers的两个neuron,它们的weight分别是,那就可以把它们排成一个matrix:,而我们的input又是一个2*1的vector:,将w和x相乘,再加上bias的vector:,就可以得到这一层的vector z,再经过activation function得到这一层的output:(activation function可以是很多类型的function,这里还是用Logistic Regression迁移过来的sigmoid function作为运算)

这里我们把所有的变量都以matrix的形式表示出来,注意的matrix,每一行对应的是一个neuron的weight,行数就是neuron的个数,列数就是feature的数量,而input x,bias b和output y都是一个列向量,行数就是feature的个数(也是neuron的个数,neuron的本质就是把feature transform到另一个space)

把这件事情写成矩阵运算的好处是,可以用GPU加速,GPU对matrix的运算是比CPU要来的快的,所以我们写neural network的时候,习惯把它写成matrix operation,然后call GPU来加速它
我们可以把hidden layers这部分,看做是一个feature extractor(特征提取器),这个feature extractor就replace了我们之前手动做feature engineering,feature transformation这些事情,经过这个feature extractor得到的output,就可以被当作一组新的feature
output layer做的事情,其实就是把它当做一个Multi-class classifier,它是拿经过feature extractor转换后的那一组比较好的feature(能够被很好地separate)进行分类的,由于我们把output layer看做是一个Multi-class classifier,所以我们会在最后一个layer加上softmax

这里举一个手写数字识别的例子,input是一张image,对机器来说一张image实际上就是一个vector,假设这是一张16*16的image,那它有256个pixel,对machine来说,它是一个256维的vector,image中的每一个都对应到vector中的一个dimension,简单来说,我们把黑色的pixel的值设为1,白色的pixel的值设为0
而neural network的output,如果在output layer使用了softmax,那它的output就是一个突出极大值的Probability distribution,假设我们的output是10维的话(10个数字,0~9),这个output的每一维都对应到它可能是某一个数字的机率,实际上这个neural network的作用就是计算image成为10个数字的机率各自有多少,机率最大(softmax突出极大值的意义所在)的那个数字,就是机器的预测值
在手写字体识别的demo里,我们唯一需要的就是一个function,这个function的input是一个256的vector,output是一个10维的vector,这个function就是neural network(这里我们用简单的Feedforward network)
input固定为256维,output固定为10维的feedforward neural network,实际上这个network structure就已经确定了一个function set(model)的形状,在这个function set里的每一个function都可以拿来做手写数字识别,接下来我们要做的事情是用gradient descent去计算出一组参数,挑一个最适合拿来做手写数字识别的function
所以这里很重要的一件事情是,我们要对network structure进行design,之前在做Logistic Regression或者是linear Regression的时候,我们对model的structure是没有什么好设计的,但是对neural network来说,我们现在已知的constraint只有input是256维,output是10维,而中间要有几个hidden layer,每个layer要有几个neuron,都是需要我们自己去设计的,它们近乎是决定了function set长什么样子
如果你的network structure设计的很差,这个function set里面根本就没有好的function,那就会像大海捞针一样,结果针并不在海里
input、output的dimension,加上network structure,就可以确定一个model的形状,前两个是容易知道的,而决定这个network的structure则是整个Deep Learning中最为关键的步骤
input 256维,output 10维,以及自己design的network structure 决定了 function set(model)
Q:How many layers? How many neurons for each layer?
Q:有人可能会问,机器能不能自动地学习network的structure?
Q:我们可不可以自己去design一个新的network structure,比如说可不可以不要Fully connected layers(全连接层),自己去DIY不同layers的neuron之间的连接?
定义一个function的好坏,由于现在我们做的是一个Multi-class classification,所以image为数字1的label “1”告诉我们,现在的target是一个10维的vector,只有在第一维对应数字1的地方,它的值是1,其他都是0
input这张image的256个pixel,通过这个neural network之后,会得到一个output,称之为y;而从这张image的label中转化而来的target,称之为,有了output 和target 之后,要做的事情是计算它们之间的cross entropy(交叉熵),这个做法跟我们之前做Multi-class classification的时候是一模一样的
接下来就去调整参数,让这个cross entropy越小越好,当然整个training data里面不会只有一笔data,你需要把所有data的cross entropy都sum起来,得到一个total loss ,得到loss function之后你要做的事情是找一组network的parameters:,它可以minimize这个total loss,这组parameter 对应的function就是我们最终训练好的model

那怎么去找这个使total loss minimize的呢?使用的方法就是我们的老朋友——Gradient Descent
实际上在deep learning里面用gradient descent,跟在linear regression里面使用完全没有什么差别,只是function和parameter变得更复杂了而已,其他事情都是一模一样的
现在你的里面是一大堆的weight、bias参数,先random找一个初始值,接下来去计算每一个参数对total loss的偏微分,把这些偏微分全部集合起来,就叫做gradient,有了这些偏微分以后,你就可以更新所有的参数,都减掉learning rate乘上偏微分的值,这个process反复进行下去,最终找到一组好的参数,就做完deep learning的training了

所以,其实deep learning就是这样子了,就算是alpha go,也是用gradient descent train出来的,可能在你的想象中它有多么得高大上,实际上就是在用gradient descent这样朴素的方法
你可能会问,这个gradient descent的function式子到底是长什么样子呢?之前我们都是一步一步地把那个算式推导出来的,但是在neural network里面,有成百上千个参数,如果要一步一步地人工推导并求微分的话是比较困难的,甚至是不可行的
其实,在现在这个时代,我们不需要像以前一样自己去implement Backpropagation(反向传播),因为有太多太多的toolkit可以帮你计算Backpropagation,比如tensorflow、pytorch
注:Backpropagation就是算微分的一个比较有效的方式
最后还有一个问题,为什么我们要deep learning?一个很直觉的答案是,越deep,performance就越好,一般来说,随着deep learning中的layers数量增加,error率不断降低
但是,稍微有一点machine learning常识的人都不会觉得太surprise,因为本来model的parameter越多,它cover的function set就越大,它的bias就越小,如果今天你有足够多的training data去控制它的variance,一个比较复杂、参数比较多的model,它performance比较好,是很正常的,那变deep有什么特别了不起的地方?
甚至有一个理论是这样说的,任何连续的function,它input是一个N维的vector,output是一个M维的vector,它都可以用一个hidden layer的neural network来表示,只要你这个hidden layer的neuron够多,它可以表示成任何的function,既然一个hidden layer的neural network可以表示成任何的function,而我们在做machine learning的时候,需要的东西就只是一个function而已,那做deep有什么特殊的意义呢?
所以有人说,deep learning就只是一个噱头而已,因为做deep感觉比较潮,如果你只是增加neuron把它变宽,变成fat neural network,那就感觉太“虚弱”了,所以我们要做deep learning,给它增加layers而不是增加neuron。
真的是这样吗?后面的章节会解释这件事情:DNN(deep) is better than FNN(fat)
其实network structure的design是一件蛮难的事情,我们到底要怎么决定layer的数目和每一个layer的neuron的数目呢?其实这个只能够凭着经验和直觉、多方面的尝试,有时候甚至会需要一些domain knowledge(专业领域的知识),从非deep learning的方法到deep learning的方法,并不是说machine learning比较简单,而是我们把一个问题转化成了另一个问题
本来不是deep learning的model,要得到一个好的结果,往往需要做feature engineering(特征工程),也就是做feature transform,然后找一组好的feature;一开始学习deep learning的时候,好像会觉得deep learning的layers之间也是在做feature transform,但实际上在做deep learning的时候,往往不需要一个好的feature ,比如说在做影像辨识的时候,你可以把所有的pixel直接丢进去,但是在过去做图像识别,你是需要对图像抽取出一些人定的feature出来的,这件事情就是feature transform,但是有了deep learning之后,你完全可以直接丢pixel进去硬做
但是,今天deep learning制造了一个新的问题,它所制造的问题就是,你需要去design network的structure,所以你的问题从本来的如何抽取feature转化成怎么design network structure,所以deep learning是不是真的好用,取决于你觉得哪一个问题比较容易
如果是影像辨识或者是语音辨识的话,design network structure可能比feature engineering要来的容易,因为,虽然我们人都会看、会听,但是这件事情,它太过潜意识了,它离我们意识的层次太远,我们无法意识到,我们到底是怎么做语音辨识这件事情,所以对人来说,你要抽一组好的feature,让机器可以很方便地用linear的方法做语音辨识,其实是很难的,因为人根本就不知道好的feature到底长什么样子;所以还不如design一个network structure,或者是尝试各种network structure,让machine自己去找出好的feature,这件事情反而变得比较容易,对影像来说也是一样的
有这么一个说法:deep learning在NLP上面的performance并没有那么好。语音辨识和影像辨识这两个领域是最早开始用deep learning的,一用下去进步量就非常地惊人,比如错误率一下子就降低了20%这样,但是在NLP上,它的进步量似乎并没有那么惊人,甚至有很多做NLP的人,现在认为说deep learning不见得那么work,这个原因可能是,人在做NLP这件事情的时候,由于人在文字处理上是比较强的,比如叫你设计一个rule去detect一篇document是正面的情绪还是负面的情绪,你完全可以列表,列出一些正面情绪和负面情绪的词汇,然后看这个document里面正面情绪的词汇出现的百分比是多少,你可能就可以得到一个不错的结果。所以NLP这个task,对人来说是比较容易设计rule的,你设计的那些ad-hoc(特别的)的rule,往往可以得到一个还不错的结果,这就是为什么deep learning相较于NLP传统的方法,觉得没有像其他领域一样进步得那么显著(但还是有一些进步的)
长久而言,可能文字处理中会有一些隐藏的资讯是人自己也不知道的,所以让机器自己去学这件事情,还是可以占到一些优势,只是眼下它跟传统方法的差异看起来并没有那么的惊人,但还是有进步的
Backpropagation(反向传播),就是告诉我们用gradient descent来train一个neural network的时候该怎么做,它只是求微分的一种方法,而不是一种新的算法
gradient descent的使用方法,跟前面讲到的linear Regression或者是Logistic Regression是一模一样的,唯一的区别就在于当它用在neural network的时候,network parameters 里面可能会有将近million个参数
所以现在最大的困难是,如何有效地把这个近百万维的vector给计算出来,这就是Backpropagation要做的事情,所以Backpropagation并不是一个和gradient descent不同的training的方法,它就是gradient descent,它只是一个比较有效率的算法,让你在计算这个gradient的vector的时候更有效率
Backpropagation里面并没有什么高深的数学,你唯一需要记得的就只有Chain Rule(链式法则)
对整个neural network,我们定义了一个loss function:,它等于所有training data的loss之和
我们把training data里任意一个样本点代到neural network里面,它会output一个,我们把这个output跟样本点本身的label标注的target 作cross entropy,这个交叉熵定义了output 和target 之间的距离,如果cross entropy比较大的话,说明output和target之间距离很远,这个network的parameter的loss是比较大的,反之则说明这组parameter是比较好的。
然后summation over所有training data的cross entropy ,得到total loss ,这就是我们的loss function,用这个对某一个参数w做偏微分,表达式如下:
这个表达式告诉我们,只需要考虑如何计算对某一笔data的,再将所有training data的cross entropy对参数w的偏微分累计求和,就可以把total loss对某一个参数w的偏微分给计算出来
我们先考虑某一个neuron,假设只有两个input ,通过这个neuron,我们先得到,然后经过activation function从这个neuron中output出来,作为后续neuron的input,再经过了非常非常多的事情以后,会得到最终的output
现在的问题是这样:该怎么算?按照chain rule,可以把它拆分成两项,,这两项分别去把它计算出来。前面这一项是比较简单的,后面这一项是比较复杂的
计算前面这一项的这个process,我们称之为Forward pass;而计算后面这项的process,我们称之为Backward pass
先考虑这一项,完全可以秒算出来,
它的规律是这样的:求,就是看w前面连接的input是什么,那微分后的值就是什么,因此只要计算出neural network里面每一个neuron的output就可以知道任意的z对w的偏微分
再考虑这一项,它是比较复杂的,这里我们假设activation function是sigmoid function
我们的z通过activation function得到a,这个neuron的output是,接下来这个a会乘上某一个weight ,再加上其它一大堆的value得到,它是下一个neuron activation function的input,然后a又会乘上另一个weight ,再加上其它一堆value得到,后面还会发生很多很多其他事情,不过这里我们就只先考虑下一步会发生什么事情:
这里的实际上就是activation function的微分(在这里就是sigmoid function的微分),接下来的问题是应该长什么样子呢?a会影响和,而和会影响,所以通过chain rule可以得到
这里的,,那和又该怎么算呢?这里先假设我们已经通过某种方法把和这两项给算出来了,然后回过头去就可以把给轻易地算出来

这个式子还是蛮简单的,然后,我们可以从另外一个观点来看待这个式子
你可以想象说,现在有另外一个neuron,它不在我们原来的network里面,在下图中它被画成三角形,这个neuron的input就是和,那input 就乘上,input 就乘上,它们两个相加再乘上activation function的微分 ,就可以得到output

这张图描述了一个新的“neuron”,它的含义跟图下方的表达式是一模一样的,作这张图的目的是为了方便理解
值得注意的是,这里的是一个constant常数,它并不是一个function,因为z其实在计算forward pass的时候就已经被决定好了,z是一个固定的值
所以这个neuron其实跟我们之前看到的sigmoid function是不一样的,它并不是把input通过一个non-linear进行转换,而是直接把input乘上一个constant ,就得到了output,因此这个neuron被画成三角形,代表它跟我们之前看到的圆形的neuron的运作方式是不一样的,它是直接乘上一个constant(这里的三角形有点像电路里的运算放大器op-amp,它也是乘上一个constant)
ok,现在我们最后需要解决的问题是,怎么计算和这两项,假设有两个不同的case:
假设蓝色的这个neuron已经是hidden layer的最后一层了,也就是说连接在和后的这两个红色的neuron已经是output layer,它的output就已经是整个network的output了,这个时候计算就比较简单
其中就是output layer的activation function (softmax) 对的偏微分
而就是loss对的偏微分,它取决于你的loss function是怎么定义的,也就是你的output和target之间是怎么evaluate的,你可以用cross entropy,也可以用mean square error,用不同的定义,的值就不一样
这个时候,你就已经可以把对和的偏微分、算出来了

假设现在红色的neuron并不是整个network的output,那经过红色neuron的activation function得到,然后output 和、相乘并加上一堆其他东西分别得到和,如下图所示

根据之前的推导证明类比,如果知道和,我们就可以计算,如下图所示,借助运算放大器的辅助理解,将乘上和乘上的值加起来再通过op-amp,乘上放大系数,就可以得到output

知道和就可以知道,知道和就可以知道,...... ,现在这个过程就可以反复进行下去,直到找到output layer,我们可以算出确切的值,然后再一层一层反推回去
你可能会想说,这个方法听起来挺让人崩溃的,每次要算一个微分的值,都要一路往后走,一直走到network的output,如果写成表达式的话,一层一层往后展开,感觉会是一个很可怕的式子,但是!实际上并不是这个样子做的
你只要换一个方向,从output layer的开始算,你就会发现它的运算量跟原来的network的Feedforward path其实是一样的
假设现在有6个neuron,每一个neuron的activation function的input分别是、、、、、,我们要计算对这些的偏微分,按照原来的思路,我们想要知道的偏微分,就要去算和的偏微分,想要知道和的偏微分,就又要去计算两遍和的偏微分,因此如果我们是从、的偏微分开始算,那就没有效率
但是,如果你反过来先去计算和的偏微分的话,这个process,就突然之间变得有效率起来了,我们先去计算和,然后就可以算出和,最后就可以算出和,而这一整个过程,就可以转化为op-amp运算放大器的那张图

这里每一个op-amp的放大系数就是、、、,所以整一个流程就是,先快速地计算出和,然后再把这两个偏微分的值乘上路径上的weight汇集到neuron上面,再通过op-amp的放大,就可以得到和这两个偏微分的值,再让它们乘上一些weight,并且通过一个op-amp,就得到和这两个偏微分的值,这样就计算完了,这个步骤,就叫做Backward pass
在做Backward pass的时候,实际上的做法就是建另外一个neural network,本来正向neural network里面的activation function都是sigmoid function,而现在计算Backward pass的时候,就是建一个反向的neural network,它的activation function就是一个运算放大器op-amp,要先算完Forward pass后,才算得出来。每一个反向neuron的input是loss 对后面一层layer的的偏微分,output则是loss 对这个neuron的的偏微分,做Backward pass就是通过这样一个反向neural network的运算,把loss 对每一个neuron的的偏微分都给算出来
注:如果是正向做Backward pass的话,实际上每次计算一个,就需要把该neuron后面所有的都给计算一遍,会造成很多不必要的重复运算,如果写成code的形式,就相当于调用了很多次重复的函数;而如果是反向做Backward pass,实际上就是把这些调用函数的过程都变成调用“值”的过程,因此可以直接计算出结果,而不需要占用过多的堆栈空间
最后,我们来总结一下Backpropagation是怎么做的
Forward pass,每个neuron的activation function的output,就是它所连接的weight的
Backward pass,建一个与原来方向相反的neural network,它的三角形neuron的output就是
把通过forward pass得到的和通过backward pass得到的乘起来就可以得到对的偏微分

本文会顺带解决CNN部分的两个问题:
1、max pooling架构中用到的max无法微分,那在gradient descent的时候该如何处理?
2、L1 的Regression到底是什么东西
本文的主要思路:
针对training set和testing set上的performance分别提出针对性的解决方法
1、在training set上准确率不高:
new activation function:ReLU、Maxout
adaptive learning rate:Adagrad、RMSProp、Momentum、Adam
2、在testing set上准确率不高:Early Stopping、Regularization or Dropout
Recipe,配方、秘诀,这里指的是做deep learning的流程应该是什么样子
我们都已经知道了deep learning的三个步骤
做完这些事情以后,你会得到一个更好的neural network,那接下来你要做什么事情呢?

你要做的第一件事是,提高model在training set上的正确率
先检查training set的performance其实是deep learning一个非常unique的地方,如果今天你用的是k-nearest neighbor或decision tree这类非deep learning的方法,做完以后你其实会不太想检查training set的结果,因为在training set上的performance正确率就是100,没有什么好检查的
有人说deep learning的model里这么多参数,感觉很容易overfitting的样子,但实际上这个deep learning的方法,它才不容易overfitting,我们说的overfitting就是在training set上performance很好,但在testing set上performance没有那么好;只有像k nearest neighbor,decision tree这类方法,它们在training set上正确率都是100,这才是非常容易overfitting的,而对deep learning来说,overfitting往往不会是你遇到的第一个问题
因为你在training的时候,deep learning并不是像k nearest neighbor这种方法一样,一训练就可以得到非常好的正确率,它有可能在training set上根本没有办法给你一个好的正确率,所以,这个时候你要回头去检查在前面的step里面要做什么样的修改,好让你在training set上可以得到比较高的正确率
接下来你要做的事是,提高model在testing set上的正确率
假设现在你已经在training set上得到好的performance了,那接下来就把model apply到testing set上,我们最后真正关心的,是testing set上的performance,假如得到的结果不好,这个情况下发生的才是Overfitting,也就是在training set上得到好的结果,却在testing set上得到不好的结果
那你要回过头去做一些事情,试着解决overfitting,但有时候你加了新的technique,想要overcome overfitting这个problem的时候,其实反而会让training set上的结果变坏;所以你在做完这一步的修改以后,要先回头去检查新的model在training set上的结果,如果这个结果变坏的话,你就要从头对network training的process做一些调整,那如果你同时在training set还有testing set上都得到好结果的话,你就成功了,最后就可以把你的系统真正用在application上面了
不要看到所有不好的performance就归责于overfitting
先看右边testing data的图,横坐标是model做gradient descent所update的次数,纵坐标则是error rate(越低说明model表现得越好),黄线表示的是20层的neural network,红色表示56层的neural network
你会发现,这个56层network的error rate比较高,它的performance比较差,而20层network的performance则是比较好的,有些人看到这个图,就会马上得到一个结论:56层的network参数太多了,56层果然没有必要,这个是overfitting。但是,真的是这样子吗?

你在说结果是overfitting之前,有检查过training set上的performance吗?对neural network来说,在training set上得到的结果很可能会像左边training error的图,也就是说,20层的network本来就要比56层的network表现得更好,所以testing set得到的结果并不能说明56层的case就是发生了overfitting
在做neural network training的时候,有太多太多的问题可以让你的training set表现的不好,比如说我们有local minimum的问题,有saddle point的问题,有plateau的问题...所以这个56层的neural network,有可能在train的时候就卡在了一个local minimum的地方,于是得到了一个差的参数,但这并不是overfitting,而是在training的时候就没有train好
有人认为这个问题叫做underfitting,但我的理解上,underfitting的本意应该是指这个model的complexity不足,这个model的参数不够多,所以它的能力不足以解出这个问题;但这个56层的network,它的参数是比20层的network要来得多的,所以它明明有能力比20层的network要做的更好,却没有得到理想的结果,这种情况不应该被称为underfitting,其实就只是没有train好而已
当你在deep learning的文献上看到某种方法的时候,永远要想一下,这个方法是要解决什么样的问题,因为在deep learning里面,有两个问题:
当只有一个方法propose(提出)的时候,它往往只针对这两个问题的其中一个来做处理,举例来说,deep learning有一个很潮的方法叫做dropout,那很多人就会说,哦,这么潮的方法,所以今天只要看到performance不好,我就去用dropout;但是,其实只有在testing的结果不好的时候,才可以去apply dropout,如果你今天的问题只是training的结果不好,那你去apply dropout,只会越train越差而已
所以,你必须要先想清楚现在的问题到底是什么,然后再根据这个问题去找针对性的方法,而不是病急乱投医,甚至是盲目诊断
下面我们分别从Training data和Testing data两个问题出发,来讲述一些针对性优化的方法
这一部分主要讲述如何在Training data上得到更好的performance,分为两个模块,New activation function和Adaptive Learning Rate
这个部分主要讲述的是关于Recipe of Deep Learning中New activation function的一些理论
如果你今天的training结果不好,很有可能是因为你的network架构设计得不好。举例来说,可能你用的activation function是对training比较不利的,那你就尝试着换一些新的activation function,也许可以带来比较好的结果
在1980年代,比较常用的activation function是sigmoid function,如果现在我们使用sigmoid function,你会发现deeper不一定imply better,在MNIST手写数字识别上training set的结果,当layer越来越多的时候,accuracy一开始持平,后来就掉下去了,在layer是9层、10层的时候,整个结果就崩溃了;但注意!9层、10层的情况并不能被认为是因为参数太多而导致overfitting,实际上这只是training set的结果,你都不知道testing的情况,又哪来的overfitting之说呢?
上面这个问题的原因不是overfitting,而是Vanishing Gradient(梯度消失),解释如下:
当你把network叠得很深的时候,在靠近input的地方,这些参数的gradient(即对最后loss function的微分)是比较小的;而在比较靠近output的地方,它对loss的微分值会是比较大的
因此当你设定同样learning rate的时候,靠近input的地方,它参数的update是很慢的;而靠近output的地方,它参数的update是比较快的
所以在靠近input的地方,参数几乎还是random的时候,output就已经根据这些random的结果找到了一个local minima,然后就converge(收敛)了
这个时候你会发现,参数的loss下降的速度变得很慢,你就会觉得gradient已经接近于0了,于是把程序停掉了,由于这个converge,是几乎base on random的参数,所以model的参数并没有被训练充分,那在training data上得到的结果肯定是很差的

为什么会有这个现象发生呢?如果你自己把Backpropagation的式子写出来的话,就可以很轻易地发现用sigmoid function会导致这件事情的发生;但是,我们今天不看Backpropagation的式子,其实从直觉上来想你也可以了解这件事情发生的原因
某一个参数对total loss 的偏微分,即gradient ,它直觉的意思是说,当我今天把这个参数做小小的变化的时候,它对这个loss 的影响有多大;那我们就把第一个layer里的某一个参数加上,看看对network的output和target之间的loss有什么样的影响
通过sigmoid function之后,得到output是会变小的,改变某一个参数的weight,会对某个neuron的output值产生影响,但是这个影响是会随着层数的递增而衰减的,sigmoid function的形状如下所示,它会把负无穷大到正无穷大之间的值都硬压到0~1之间,把较大的input压缩成较小的output

因此即使值很大,但每经过一个sigmoid function就会被缩小一次,所以network越深,被衰减的次数就越多,直到最后,它对output的影响就是比较小的,相应的也导致input对loss的影响会比较小,于是靠近input的那些weight对loss的gradient 远小于靠近output的gradient

那怎么解决这个问题呢?比较早年的做法是去train RBM,做layer-wise pre-training,它的精神就是,先把第一个layer train好,再去train第二个,然后再第三个...所以最后你在做Backpropagation的时候,尽管第一个layer几乎没有被train到,但一开始在做pre-train的时候就已经把它给pre-train好了,这就是RBM做pre-train有用的原因。可以在一定程度上解决问题
但其实改一下activation function可能就可以handle这个问题了
现在比较常用的activation function叫做Rectified Linear Unit(整流线性单元函数,又称修正线性单元),它的缩写是ReLU,该函数形状如下图所示,z为input,a为output,如果input>0则output = input,如果input<0则output = 0

选择ReLU的理由如下:
下图是ReLU的neural network,以ReLU作为activation function的neuron,它的output要么等于0,要么等于input
当output=input的时候,这个activation function就是linear的;而output=0的neuron对整个network是没有任何作用的,因此可以把它们从network中拿掉

拿掉所有output为0的neuron后如下图所示,此时整个network就变成a thinner linear network,linear的好处是,output=input,不会像sigmoid function一样使input产生的影响逐层递减

Q:这里就会有一个问题,我们之所以使用deep learning,就是因为想要一个non-linear、比较复杂的function,而使用ReLU不就会让它变成一个linear function吗?这样得到的function不是会变得很弱吗?
A:其实,使用ReLU之后的network整体来说还是non-linear的,如果你对input做小小的改变,不改变neuron的operation region的话,那network就是一个linear function;但是,如果你对input做比较大的改变,导致neuron的operation region被改变的话,比如从output=0转变到了output=input,network整体上就变成了non-linear function
注:这里的region是指input z<0和input z>0的两个范围
Q:还有另外一个问题,我们对loss function做gradient descent,要求neural network是可以做微分的,但ReLU是一个分段函数,它是不能微分的(至少在z=0这个点是不可微的),那该怎么办呢?
A:在实际操作上,当region的范围处于z>0时,微分值gradient就是1;当region的范围处于z<0时,微分值gradient就是0;当z为0时,就不要管它
其实ReLU还存在一定的问题,比如当input<0的时候,output=0,此时微分值gradient也为0,你就没有办法去update参数了,所以我们应该让input<0的时候,微分后还能有一点点的值,比如令,这个东西就叫做Leaky ReLU

既然a可以等于0.01z,那这个z的系数可不可以是0.07、0.08之类呢?所以就有人提出了Parametric ReLU,也就是令,其中并不是固定的值,而是network的一个参数,它可以通过training data学出来,甚至每个neuron都可以有不同的值
这个时候又有人想,为什么一定要是ReLU这样子呢,activation function可不可以有别的样子呢?所以后来有了一个更进阶的想法,叫做Maxout network
Maxout的想法是,让network自动去学习它的activation function,那Maxout network就可以自动学出ReLU,也可以学出其他的activation function,这一切都是由training data来决定的
假设现在有input ,它们乘上几组不同的weight分别得到5,7,-1,1,这些值本来是不同neuron的input,它们要通过activation function变为neuron的output;但在Maxout network里,我们事先决定好将某几个“neuron”的input分为一个group,比如5,7分为一个group,然后在这个group里选取一个最大值7作为output

这个过程就好像在一个layer上做Max Pooling一样,它和原来的network不同之处在于,它把原来几个“neuron”的input按一定规则组成了一个group,然后并没有使它们通过activation function,而是选取其中的最大值当做这几个“neuron”的output
当然,实际上原来的”neuron“早就已经不存在了,这几个被合并的“neuron”应当被看做是一个新的neuron,这个新的neuron的input是原来几个“neuron”的input组成的vector,output则取input的最大值,而并非由activation function产生
在实际操作上,几个element被分为一个group这件事情是由你自己决定的,它就是network structure里一个需要被调的参数,不一定要跟上图一样两个分为一组
Maxout是如何模仿出ReLU这个activation function的呢?
下图左上角是一个ReLU的neuron,它的input x会乘上neuron的weight w,再加上bias b,然后通过activation function-ReLU,得到output a

如果我们使用的是上图右上角所示的Maxout network,假设的参数w和b与ReLU的参数一致,而的参数w和b全部设为0,然后做Max Pooling,选取较大值作为a
neuron的input为
neuron的output为,为上图右下角绿线
你会发现,此时ReLU和Maxout所得到的output是一模一样的,它们是相同的activation function
除了ReLU,Maxout还可以实现更多不同的activation function
比如的参数w和b不是0,而是,此时
neuron的input为
neuron的output为,为下图右下角绿线

这个时候你得到的activation function的形状(绿线形状),是由network的参数决定的,因此它是一个Learnable Activation Function,具体的形状可以根据training data去generate出来
Maxout可以实现任何piecewise linear convex activation function(分段线性凸激活函数),其中这个activation function被分为多少段,取决于你把多少个element z放到一个group里,下图分别是2个element一组和3个element一组的activation function的不同形状

接下来我们要面对的是,怎么去train一个Maxout network,如何解决Max不能微分的问题
假设在下面的Maxout network中,红框内为每个neuron的output

其实Max operation就是linear的operation,只是它仅接在前面这个group里的某一个element上,因此我们可以把那些并没有被Max连接到的element通通拿掉,从而得到一个比较细长的linear network
实际上我们真正训练的并不是一个含有max函数的network,而是一个化简后如下图所示的linear network;当我们还没有真正开始训练模型的时候,此时这个network含有max函数无法微分,但是只要真的丢进去了一笔data,network就会马上根据这笔data确定具体的形状,此时max函数的问题已经被实际数据给解决了,所以我们完全可以根据这笔training data使用Backpropagation的方法去训练被network留下来的参数
所以我们担心的max函数无法微分,它只是理论上的问题;在具体的实践上,我们完全可以先根据data把max函数转化为某个具体的函数,再对这个转化后的thiner linear network进行微分

这个时候你也许会有一个问题,如果按照上面的做法,那岂不是只会train留在network里面的那些参数,剩下的参数该怎么办?那些被拿掉的直线(weight)岂不是永远也train不到了吗?
其实这也只是个理论上的问题,在实际操作上,我们之前已经提到过,每个linear network的structure都是由input的那一笔data来决定的,当你input不同data的时候,得到的network structure是不同的,留在network里面的参数也是不同的,由于我们有很多很多笔training data,所以network的structure在训练中不断地变换,实际上最后每一个weight参数都会被train到
所以,我们回到Max Pooling的问题上来,由于Max Pooling跟Maxout是一模一样的operation,既然如何训练Maxout的问题可以被解决,那训练Max Pooling又有什么困难呢?
Max Pooling有关max函数的微分问题采用跟Maxout一样的方案即可解决,至此我们已经解决了CNN部分的第一个问题
这个部分主要讲述的是关于Recipe of Deep Learning中Adaptive learning rate的一些理论
我们之前已经了解过Adagrad的做法,让每一个parameter都要有不同的learning rate,
Adagrad的精神是,假设我们考虑两个参数,如果在这个方向上,平常的gradient都比较小,那它是比较平坦的,于是就给它比较大的learning rate;反过来说,在这个方向上,平常gradient都比较大,那它是比较陡峭的,于是给它比较小的learning rate

但我们实际面对的问题,很有可能远比Adagrad所能解决的问题要来的复杂,我们之前做Linear Regression的时候,我们做optimization的对象,也就是loss function,它是convex的形状;但实际上我们在做deep learning的时候,这个loss function可以是任何形状
loss function可以是任何形状,对convex loss function来说,在每个方向上它会一直保持平坦或陡峭的状态,所以你只需要针对平坦的情况设置较大的learning rate,对陡峭的情况设置较小的learning rate即可
但是在下图所示的情况中,即使是在同一个方向上(如w1方向),loss function也有可能一会儿平坦一会儿陡峭,所以你要随时根据gradient的大小来快速地调整learning rate

所以真正要处理deep learning的问题,用Adagrad可能是不够的,你需要更dynamic的调整learning rate的方法,所以产生了Adagrad的进阶版——RMSProp
RMSprop还是一个蛮神奇的方法,因为它并不是在paper里提出来的,而是Hinton在mooc的course里面提出来的一个方法,所以需要cite(引用)的时候,要去cite Hinton的课程链接
RMSProp的做法如下:
我们的learning rate依旧设置为一个固定的值 除掉一个变化的值 ,这个等于上一个和当前梯度的加权方均根(特别的是,在第一个时间点,就是第一个算出来的gradient值),即:
这里的值是可以自由调整的,RMSProp跟Adagrad不同之处在于,Adagrad的分母是对过程中所有的gradient取平方和开根号,也就是说Adagrad考虑的是整个过程平均的gradient信息;而RMSProp虽然也是对所有的gradient进行平方和开根号,但是它用一个来调整对不同gradient的使用程度,比如你把α的值设的小一点,意思就是你更倾向于相信新的gradient所告诉你的error surface的平滑或陡峭程度,而比较无视于旧的gradient所提供给你的information

所以当你做RMSProp的时候,一样是在算gradient的root mean square,但是你可以给现在已经看到的gradient比较大的weight,给过去看到的gradient比较小的weight,来调整对gradient信息的使用程度
除了learning rate的问题以外,在做deep learning的时候,也会出现卡在local minimum、saddle point或是plateau的地方,很多人都会担心,deep learning这么复杂的model,可能非常容易就会被卡住了
但其实Yann LeCun在07年的时候,就提出了一个蛮特别的说法,他说你不要太担心local minima的问题,因为一旦出现local minima,它就必须在每一个dimension都是下图中这种山谷的低谷形状,假设山谷的低谷出现的概率为p,由于我们的network有非常非常多的参数,这里假设有1000个参数,每一个参数都要位于山谷的低谷之处,这件事发生的概率为,当你的network越复杂,参数越多,这件事发生的概率就越低

所以在一个很大的neural network里面,其实并没有那么多的local minima,搞不好它看起来其实是很平滑的,所以当你走到一个你觉得是local minima的地方被卡住了,那它八成就是global minima,或者是很接近global minima的地方
有一个heuristic(启发性)的方法可以稍微处理一下上面所说的“卡住”的问题,它的灵感来自于真实世界
假设在有一个球从左上角滚下来,它会滚到plateau的地方、local minima的地方,但是由于惯性它还会继续往前走一段路程,假设前面的坡没有很陡,这个球就很有可能翻过山坡,走到比local minima还要好的地方

所以我们要做的,就是把惯性塞到gradient descent里面,这件事情就叫做Momentum
当我们在gradient descent里加上Momentum的时候,每一次update的方向,不再只考虑gradient的方向,还要考虑上一次update的方向,那这里我们就用一个变量去记录前一个时间点update的方向
随机选一个初始值,初始化,接下来计算处的gradient,然后我们要移动的方向是由前一个时间点的移动方向和gradient的反方向来决定的,即
注:这里的也是一个手动调整的参数,它表示惯性对前进方向的影响有多大
接下来我们第二个时间点要走的方向,它是由第一个时间点移动的方向和gradient的反方向共同决定的;是图中的绿色虚线,它代表由于上一次的惯性想要继续走的方向;是图中的红色虚线,它代表这次gradient告诉你所要移动的方向;它们的矢量和就是这一次真实移动的方向,为蓝色实线

gradient告诉我们走红色虚线的方向,惯性告诉我们走绿色虚线的方向,合起来就是走蓝色的方向
我们还可以用另一种方法来理解Momentum这件事,其实你在每一个时间点移动的步伐,包括大小和方向,就是过去所有gradient的加权和
具体推导如下图所示,第一个时间点移动的步伐是处的gradient加权,第二个时间点移动的步伐是和处的gradient加权和...以此类推;由于的值小于1,因此该加权意味着越是之前的gradient,它的权重就越小,也就是说,你更在意的是现在的gradient,但是过去的所有gradient也要对你现在update的方向有一定程度的影响力,这就是Momentum

如果你对数学公式不太喜欢的话,那我们就从直觉上来看一下加入Momentum之后是怎么运作的
在加入Momentum以后,每一次移动的方向,就是negative的gradient加上Momentum建议我们要走的方向,Momentum其实就是上一个时间点的movement
下图中,红色实线是gradient建议我们走的方向,直观上看就是根据坡度要走的方向;绿色虚线是Momentum建议我们走的方向,实际上就是上一次移动的方向;蓝色实线则是最终真正走的方向

如果我们今天走到local minimum的地方,此时gradient是0,红色箭头没有指向,它就会告诉你就停在这里吧,但是Momentum也就是绿色箭头,它指向右侧就是告诉你之前是要走向右边的,所以你仍然应该要继续往右走,所以最后你参数update的方向仍然会继续向右;你甚至可以期待Momentum比较强,惯性的力量可以支撑着你走出这个谷底,去到loss更低的地方
其实RMSProp加上Momentum,就可以得到Adam
根据下面的paper来快速描述一下Adam的algorithm:
先初始化,就是Momentum中,前一个时间点的movement
再初始化,就是RMSProp里计算gradient的root mean square的
最后初始化,t用来表示时间点
先算出gradient
再根据过去要走的方向和gradient ,算出现在要走的方向 ——Momentum
然后根据前一个时间点的和gradient 的平方,算一下放在分母的——RMSProp
接下来做了一个原来RMSProp和Momentum里没有的东西,就是bias correction,它使和都除上一个值,这个值本来比较小,后来会越来越接近于1 (原理详见paper)
最后做update,把Momentum建议你的方向乘上learning rate ,再除掉RMSProp normalize后建议的learning rate分母,然后得到update的方向

这一部分主要讲述如何在Testing data上得到更好的performance,分为三个模块,Early Stopping、Regularization和Dropout
值得注意的是,Early Stopping和Regularization是很typical的做法,它们不是特别为deep learning所设计的;而Dropout是一个蛮有deep learning特色的做法
假设你今天的learning rate调的比较好,那随着训练的进行,total loss通常会越来越小,但是Training set和Testing set的情况并不是完全一样的,很有可能当你在Training set上的loss逐渐减小的时候,在Testing set上的loss反而上升了
所以,理想上假如你知道testing data上的loss变化情况,你会在testing set的loss最小的时候停下来,而不是在training set的loss最小的时候停下来;但testing set实际上是未知的东西,所以我们需要用validation set来替代它去做这件事情

注:很多时候,我们所讲的“testing set”并不是指代那个未知的数据集,而是一些已知的被你拿来做测试之用的数据集,比如kaggle上的public set,或者是你自己切出来的validation set
regularization就是在原来的loss function上额外增加几个term,比如我们要minimize的loss function原先应该是square error或cross entropy,那在做Regularization的时候,就在后面加一个Regularization的term
regularization term可以是参数的L2 norm(L2正规化),所谓的L2 norm,就是把model参数集里的每一个参数都取平方然后求和,这件事被称作L2 regularization,即

通常我们在做regularization的时候,新加的term里是不会考虑bias这一项的,因为加regularization的目的是为了让我们的function更平滑,而bias通常是跟function的平滑程度没有关系的
你会发现我们新加的regularization term 里有一个,由于我们是要对loss function求微分的,而新加的regularization term是参数的平方和,对平方求微分会多出来一个系数2,我们的就是用来和这个2相消的
L2 regularization具体工作流程如下:
如果把这个推导出来的式子和原式作比较,你会发现参数在每次update之前,都会乘上一个,而和通常会被设为一个很小的值,因此通常是一个接近于1的值,比如0.99,;也就是说,regularization做的事情是,每次update参数之前,不分青红皂白就先对原来的乘个0.99,这意味着,随着update次数增加,参数会越来越接近于0
Q:你可能会问,要是所有的参数都越来越靠近0,那最后岂不是通通变成0,得到的network还有什么用?
A:其实不会出现最后所有参数都变为0的情况,因为通过微分得到的这一项是会和前面这一项最后取得平衡的
使用L2 regularization可以让weight每次都变得更小一点,这就叫做Weight Decay(权重衰减)
除了L2 regularization中使用平方项作为new term之外,还可以使用L1 regularization,把平方项换成每一个参数的绝对值,即
Q:你的第一个问题可能会是,绝对值不能微分啊,该怎么处理呢?
A:实际上绝对值就是一个V字形的函数,在V的左边微分值是-1,在V的右边微分值是1,只有在0的地方是不能微分的,那真的走到0的时候就胡乱给它一个值,比如0,就ok了
如果w是正的,那微分出来就是+1,如果w是负的,那微分出来就是-1,所以这边写了一个w的sign function,它的意思是说,如果w是正数的话,这个function output就是+1,w是负数的话,这个function output就是-1
L1 regularization的工作流程如下:
这个式子告诉我们,每次update的时候,不管三七二十一都要减去一个,如果w是正的,sgn是+1,就会变成减一个positive的值让你的参数变小;如果w是负的,sgn是-1,就会变成加一个值让你的参数变大;总之就是让它们的绝对值减小至接近于0
我们来对比一下L1和L2的update过程:
L1和L2,虽然它们同样是让参数的绝对值变小,但它们做的事情其实略有不同:
因此,当参数w的绝对值比较大的时候,L2会让w下降得更快,而L1每次update只让w减去一个固定的值,train完以后可能还会有很多比较大的参数;当参数w的绝对值比较小的时候,L2的下降速度就会变得很慢,train出来的参数平均都是比较小的,而L1每次下降一个固定的value,train出来的参数是比较sparse的,这些参数有很多是接近0的值,也会有很大的值
在之前所讲的CNN的task里,用L1做出来的效果是比较合适的,是比较sparse的
之前提到了Weight Decay,那实际上我们在人脑里面也会做Weight Decay
下图分别描述了,刚出生的时候,婴儿的神经是比较稀疏的;6岁的时候,就会有很多很多的神经;但是到14岁的时候,神经间的连接又减少了,所以neural network也会跟我们人有一些很类似的事情,如果有一些weight你都没有去update它,那它每次都会越来越小,最后就接近0然后不见了
这跟人脑的运作,是有异曲同工之妙
ps:在deep learning里面,regularization虽然有帮助,但它的重要性往往没有SVM这类方法来得高,因为我们在做neural network的时候,通常都是从一个很小的、接近于0的值开始初始参数的,而做update的时候,通常都是让参数离0越来越远,但是regularization要达到的目的,就是希望我们的参数不要离0太远
如果你做的是Early Stopping,它会减少update的次数,其实也会避免你的参数离0太远,这跟regularization做的事情是很接近的
所以在neural network里面,regularization的作用并没有SVM来的重要,SVM其实是explicitly把regularization这件事情写在了它的objective function(目标函数)里面,SVM是要去解一个convex optimization problem,因此它解的时候不一定会有iteration的过程,它不会有Early Stopping这件事,而是一步就可以走到那个最好的结果了,所以你没有办法用Early Stopping防止它离目标太远,你必须要把regularization explicitly加到你的loss function里面去
在deep learning里面,regularization虽然有帮助,但是重要性相比其他方法(svm)没有那么高,regularization的帮助没有那么显著。Early Stop可以决定什么时候training停下来,因为我们初试参数都是给一个很小的接近0的值,做update的时候,让参数离0越来越远,而regularization做的是让参数不要离0太远,因此regularization和减少update次数(Early Stop)的效果是很接近的。因此在NeuralNetwork里面,regularization虽然也有帮助,但是帮助没有那么重要,没有重要到SVM中那样。因为SVM的参数是一步走到结果,没有Early Stop
这里先讲dropout是怎么做的,然后再来解释为什么这样做
在training的时候,每次update参数之前,我们对每一个neuron(也包括input layer的“neuron”)做sampling(抽样) ,每个neuron都有p%的机率会被丢掉,如果某个neuron被丢掉的话,跟它相连的weight也都要被丢掉
实际上就是每次update参数之前都通过抽样只保留network中的一部分neuron来做训练
做完sampling以后,network structure就会变得比较细长了,然后你再去train这个细长的network
注:每次update参数之前都要做一遍sampling,所以每次update参数的时候,拿来training的network structure都是不一样的;你可能会觉得这个方法跟前面提到的Maxout会有一点像,但实际上,Maxout是每一笔data对应的network structure不同,而Dropout是每一次update的network structure都是不同的(每一个mini-batch对应着一次update,而一个mini-batch里含有很多笔data)
当你在training的时候使用dropout,得到的performance其实是会变差的,因为某些neuron在training的时候莫名其妙就会消失不见,但这并不是问题,因为:
Dropout真正要做的事情,就是要让你在training set上的结果变差,但是在testing set上的结果是变好的
所以如果你今天遇到的问题是在training set上得到的performance不够好,你再加dropout,就只会越做越差;这告诉我们,不同的problem需要用不同的方法去解决,而不是胡乱使用,dropout就是针对testing set的方法,当然不能够拿来解决training set上的问题啦!
在使用dropout方法做testing的时候要注意两件事情:
直觉的想法是这样子:在training的时候,会丢掉一些neuron,就好像是你要练轻功的时候,会在脚上绑一些重物;然后,你在实际战斗的时候,就是实际testing的时候,是没有dropout的,就相当于把重物拿下来,所以你就会变得很强
另一个直觉的理由是这样,neural network里面的每一个neuron就是一个学生,那大家被连接在一起就是大家听到说要组队做final project,那在一个团队里总是有人会拖后腿,就是他会dropout,所以假设你觉得自己的队友会dropout,这个时候你就会想要好好做,然后去carry这个队友,这就是training的过程
那实际在testing的时候,其实大家都有好好做,没有人需要被carry,由于每个人都比一般情况下更努力,所以得到的结果会是更好的,这也就是testing的时候不做dropout的原因

直觉的解释是这样的:
假设现在的dropout rate是50%,那在training的时候,你总是期望每次update之前会丢掉一半的neuron,就像下图左侧所示,在这种情况下你learn好了一组weight参数,然后拿去testing
但是在testing的时候是没有dropout的,所以如果testing使用的是和training同一组weight,那左侧得到的output z和右侧得到的output z‘,它们的值其实是会相差两倍的,即,这样会造成testing的结果与training的结果并不match,最终的performance反而会变差

那这个时候,你就需要把右侧testing中所有的weight乘上0.5,然后做normalization,这样z就会等于z',使得testing的结果与training的结果是比较match的
在文献上有很多不同的观点来解释为什么dropout会work,其中一种比较令人信服的解释是:dropout是一种终极的ensemble的方法
ensemble的方法在比赛的时候经常用得到,它的意思是说,我们有一个很大的training set,那你每次都只从这个training set里面sample一部分的data出来,像下图一样,抽取了set1,set2,set3,set4

我们之前在讲bias和variance的trade off的时候说过,打靶有两种情况:
假设我们今天有一个很复杂的model,它往往是bias比较准,但variance很大的情况,如果你有很多个笨重复杂的model,虽然它们的variance都很大,但最后平均起来,结果往往就会很准
所以ensemble做的事情,就是利用这个特性,我们从原来的training data里面sample出很多subset,然后train很多个model,每一个model的structure甚至都可以不一样;在testing的时候,丢一笔testing data进来,使它通过所有的model,得到一大堆的结果,然后把这些结果平均起来当做最后的output

如果你的model很复杂,这一招往往是很有用的,那著名的random forest(随机森林)也是实践这个精神的一个方法,也就是如果你用一个decision tree,它就会很弱,也很容易overfitting,而如果采用random forest,它就没有那么容易overfitting
在training network的时候,每次拿一个mini-batch出来就做一次update,而根据dropout的特性,每次update之前都要对所有的neuron进行sample,因此每一个mini-batch所训练的network都是不同的
假设我们有M个neuron,每个neuron都有可能drop或不drop,所以总共可能的network数量有个;所以当你在做dropout的时候,相当于是在用很多个mini-batch分别去训练很多个network(一个mini-batch一般设置为100笔data),由于update次数是有限的,所以做了几次update,就相当于train了几个不同的network,最多可以训练到个network
每个network都只用一个minibatch的data来train,可能会让人感到不安,一个batch才100笔data,怎么train一个network呢?其实没有关系,因为这些不同的network之间的参数是shared,也就是说,虽然一个network只能用一个mini-batch来train,但同一个weight可以在不同的network里被不同的mini-batch train,所以同一个weight实际上是被所有没有丢掉它的network一起share的,它是拿所有这些network的mini-batch合起来一起train的结果
那按照ensemble这个方法的逻辑,在testing的时候,你把那train好的一大把network通通拿出来,然后把手上这一笔testing data丢到这把network里面去,每个network都给你吐出一个结果来,然后你把所有的结果平均起来 ,就是最后的output
但是在实际操作上,如下图左侧所示,这一把network实在太多了,你没有办法每一个network都丢一个input进去,再把它们的output平均起来,这样运算量太大了
所以dropout最神奇的地方是,当你并没有把这些network分开考虑,而是用一个完整的network,这个network的weight是用之前那一把network train出来的对应weight乘上(1-p%),然后再把手上这笔testing data丢进这个完整的network,得到的output跟network分开考虑的ensemble的output,是惊人的相近
也就是说下图左侧ensemble的做法和右侧dropout的做法,得到的结果是approximate(近似)的
这里用一个例子来解释:
我们train一个下图右上角所示的简单的network,它只有一个neuron,activation function是linear的,并且不考虑bias,这个network经过dropout训练以后得到的参数分别为,那给它input ,得到的output就是
如果我们今天要做ensemble的话,theoretically就是像下图这么做,每一个neuron都有可能被drop或不drop,这里只有两个input的neuron,所以我们一共可以得到2^2=4种network
我们手上这笔testing data 丢到这四个network中,分别得到4个output:,然后根据ensemble的精神,把这四个network的output通通都average起来,得到的结果是
那根据dropout的想法,我们把从training中得到的参数乘上(1-50%),作为testing network里的参数,也就是

这边想要呈现的是,在这个最简单的case里面,用不同的network structure做ensemble这件事情,跟我们用一整个network,并且把weight乘上一个值而不做ensemble所得到的output,其实是一样的
值得注意的是,只有是linear的network,才会得到上述的等价关系,如果network是非linear的,ensemble和dropout是不equivalent的;但是,dropout最后一个很神奇的地方是,虽然在non-linear的情况下,它是跟ensemble不相等的,但最后的结果还是会work
如果network很接近linear的话,dropout所得到的performance会比较好,而ReLU和Maxout的network相对来说是比较接近于linear的,所以我们通常会把含有ReLU或Maxout的network与Dropout配合起来使用
本文主要围绕Deep这个关键词展开,重点比较了shallow learning和deep learning的区别: shallow:不考虑不同input之间的关联,针对每一种class都设计了一个独立的model检测 deep:考虑了input之间的某些共同特征,所有class用同个model分类,share参数,modularization思想,hierarchy架构,更有效率地使用data和参数
我们都知道deep learning在很多问题上的表现都是比较好的,越deep的network一般都会有更好的performance
那为什么会这样呢?有一种解释是:
若随着layer层数从1到7,得到的error rate不断地降低,所以有人就认为,deep learning的表现这么好,完全就是用大量的data去硬train一个非常复杂的model而得到的结果
既然大量的data加上参数足够多的model就可以实现这个效果,那为什么一定要用DNN呢?我们完全可以用一层的shallow neural network来做同样的事情,理论上只要这一层里neuron的数目足够多,有足够的参数,就可以表示出任何函数;那DNN中deep的意义何在呢?
其实深和宽这两种结构的performance是会不一样的,这里我们就拿下面这两种结构的network做一下比较:
值得注意的是:如果要给Deep和Shallow的model一个公平的评比,你就要故意调整它们的形状,让它们的参数是一样多的,在这个情况下Shallow的model就会是一个矮胖的model,Deep的model就会是一个瘦高的model
在这个公平的评比之下,得到的结果如下图所示:
左侧表示的是deep network的情况,右侧表示的是shallow network的情况,为了保证两种情况下参数的数量是比较接近的,因此设置了右侧1*3772和1*4634这两种size大小,它们分别对应比较左侧5*2k和7*2k这两种情况下的network(注意参数数目和neuron的数目并不是等价的)

这个时候你会发现,在参数数量接近的情况下,只有1层的network,它的error rate是远大于好几层的network的;这里甚至测试了1*16k大小的shallow network,把它跟左侧也是只有一层,但是没有那么宽的network进行比较,由于参数比较多所以才略有优势;但是把1*16k大小的shallow network和参数远比它少的2*2k大小的deep network进行比较,结果竟然是后者的表现更好
也就是说,只有1层的shallow network的performance甚至都比不过很多参数比它少但层数比它多的deep network,这是为什么呢?
有人觉得deep learning就是一个暴力辗压的方法,我可以弄一个很大很大的model,然后collect一大堆的data,就可以得到比较好的performance;但根据上面的对比可知,deep learning显然是在结构上存在着某种优势,不然无法解释它会比参数数量相同的shallow learning表现得更好这个现象
DNN结构一个很大的优势是,Modularization(模块化),它用的是结构化的架构
就像写程序一样,shallow network实际上就是把所有的程序都写在了同一个main函数中,所以它去检测不同的class使用的方法是相互独立的;而deep network则是把整个任务分为了一个个小任务,每个小任务又可以不断细分下去,以形成modularization
在DNN的架构中,实际上每一层layer里的neuron都像是在解决同一个级别的任务,它们的output作为下一层layer处理更高级别任务的数据来源,低层layer里的neuron做的是对不同小特征的检测,高层layer里的neuron则根据需要挑选低层neuron所抽取出来的不同小特征,去检测一个范围更大的特征;neuron就像是一个个classifier ,后面的classifier共享前面classifier的参数
这样做的好处是,低层的neuron输出的信息可以被高层不同的neuron重复使用,而并不需要像shallow network一样,每次在用到的时候都要重新去检测一遍,因此大大降低了程序的复杂度
这里举一个分类的例子,我们要把input的人物分为四类:长头发女生、长头发男生、短头发女生、短头发男生
如果按照shallow network的想法,我们分别独立地train四个classifier(其实就相当于训练四个独立的model),然后就可以解决这个分类的问题;但是这里有一个问题,长头发男生的data是比较少的,没有太多的training data,所以,你train出来的classifier就比较weak,去detect长头发男生的performance就比较差

但其实我们的input并不是没有关联的,长头发的男生和长头发的女生都有一个共同的特征,就是长头发,因此如果我们分别独立地训练四个model作为分类器,实际上就是忽视了这个共同特征,也就是没有高效地用到data提供的全部信息,这恰恰是shallow network的弊端
而利用modularization的思想,使用deep network的架构,我们可以训练一个model作为分类器就可以完成所有的任务,我们可以把整个任务分为两个子任务:
虽然长头发的男生data很少,但长头发的人的data就很多,经过前面几层layer的特征抽取,就可以头发的data全部都丢给Classifier2,把男生或女生的data全部都丢给Classifier1,这样就真正做到了充分、高效地利用数据,Each basic classifier can have sufficient training examples,最终的Classifier再根据Classifier1和Classifier2提供的信息给出四类人的分类结果,

你会发现,经过层层layer的任务分解,其实每一个Classifier要做的事情都是比较简单的,又因为这种分层的、模组化的方式充分利用了data,并提高了信息利用的效率,所以只要用比较少的training data就可以把结果train好
做modularization的好处是把原来比较复杂的问题变得简单,比如原来的任务是检测一个长头发的女生,但现在你的任务是检测长头发和检测性别,而当检测对象变简单的时候,就算training data没有那么多,我们也可以把这个task做好,并且所有的classifier都用同一组参数检测子特征,提高了参数使用效率,这就是modularization、这就是模块化的精神
由于deep learning的deep就是在做modularization这件事,所以它需要的training data反而是比较少的,这可能会跟你的认知相反,AI=big data+deep learning,但deep learning其实是为了解决less data的问题才提出的
这边要强调的是,在做deep learning的时候,怎么做模块化这件事情是machine自动学到的,也就是说,第一层要检测什么特征、第二层要检测什么特征...这些都不是人为指定的,人只有定好有几层layer、每层layer有几个neuron,剩下的事情都是machine自己学到的
传统的机器学习算法,是人为地根据domain knowledge指定特征来进行提取,这种指定的提取方式,甚至是提取到的特征,也许并不是实际最优的,所以它的识别成功率并没有那么高;但是如果提取什么特征、怎么提取这件事让机器自己去学,它所提取的就会是那个最优解,因此识别成功率普遍会比人为指定要来的高
每一个neuron其实就是一个basic的classifier:

前面讲了deep learning的好处来自于modularization(模块化),可以用比较efficient的方式来使用data和参数,这里以语音识别为例,介绍DNN的modularization在语音领域的应用
当你说what do you think的时候,这句话其实是由一串phoneme所组成的,所谓phoneme,中文翻成音素,它是由语言学家制订的人类发音的基本单位,what由4个phoneme组成,do由两个phoneme组成,you由两个phoneme组成,等等
同样的phoneme也可能会有不太一样的发音,当你发d uw和y uw的时候,心里想要发的都是uw,但由于人类发音器官的限制,你的phoneme发音会受到前后的phoneme所影响;所以,为了表达这一件事情,我们会给同样的phoneme不同的model,这个东西就叫做tri-phone
一个phoneme可以拆成几个state,我们通常就定成3个state

以上就是人类语言的基本构架
语音辨识的过程其实非常复杂,这里只是讲语音辨识的第一步
你首先要做的事情是把acoustic feature(声学特征)转成state,这是一个单纯的classification的problem
大致过程就是在一串wave form(声音信号)上面取一个window(通常不会取太大,比如250个mini second大小),然后用acoustic feature来描述这个window里面的特性,每隔一个时间段就取一个window,一段声音信号就会变成一串vector sequence,这个就叫做acoustic feature sequence

你要建一个Classifier去识别acoustic feature属于哪个state,再把state转成phoneme,然后把phoneme转成文字,接下来你还要考虑同音异字的问题...这里不会详细讲述整个过程,而是想要比较一下过去在用deep learning之前和用deep learning之后,在语音辨识上的分类模型有什么差异
传统的方法叫做HMM-GMM
GMM,即Gaussian Mixture Model ,它假设语音里的每一个state都是相互独立的(跟前面长头发的shallow例子很像,也是假设每种情况相互独立),因此属于每个state的acoustic feature都是stationary distribution(静态分布)的,因此我们可以针对每一个state都训练一个GMM model来识别
但这个方法其实不太现实,因为要列举的model数目太多了,一般语言中英文都有30几、将近40个phoneme,那这边就假设是30个,而在tri-phone里面,每一个phoneme随着contest(上下文)的不同又有变化,假设tri-phone的形式是a-b-c,那总共就有30*30*30=27000个tri-phone,而每一个tri-phone又有三个state,每一个state都要很用一个GMM来描述,那参数实在是太多了

在有deep learning之前的传统处理方法是,让一些不同的state共享同样的model distribution,这件事情叫做Tied-state,其实实际操作上就把state当做pointer(指针),不同的pointer可能会指向同样的distribution,所以有一些state的distribution是共享的,具体哪些state共享distribution则是由语言学等专业知识决定
那这样的处理方法太粗糙了,所以又有人提出了subspace GMM,它里面其实就有modularization、有模块化的影子,它的想法是,我们先找一个Gaussian pool(里面包含了很多不同的Gaussian distribution),每一个state的information就是一个key,它告诉我们这个state要从Gaussian pool里面挑选哪些Gaussian出来
比如有某一个state 1,它挑第一、第三、第五个Gaussian;另一个state 2,它挑第一、第四、第六个Gaussian;如果你这样做,这些state有些时候就可以share部分的Gaussian,有些时候又可以完全不share Gaussian,至于要share多少Gaussian,这都是可以从training data中学出来的
HMM-GMM的方法,默认把所有的phone或者state都看做是无关联的,对它们分别训练independent model,这其实是不efficient的,它没有充分利用data提供的信息
对人类的声音来说,不同的phoneme都是由人类的发音器官所generate出来的,它们并不是完全无关的,下图画出了人类语言里面所有的元音,这些元音的发音其实就只受到三件事情的影响:
比如图中所标英文的5个元音a,e,i,o,u,当你发a到e到i的时候,舌头是由下往上;而i跟u,则是舌头放在前面或放在后面的差别;在图中同一个位置的元音,它们舌头的位置是一样的,只是嘴型不一样

如果采用deep learning的做法,就是去learn一个deep neural network,这个deep neural network的input是一个acoustic feature,它的output就是该feature属于某个state的概率,这就是一个简单的classification problem
那这边最关键的一点是,所有的state识别任务都是用同一个DNN来完成的;值得注意的是DNN并不是因为参数多取胜的,实际上在HMM-GMM里用到的参数数量和DNN其实是差不多的,区别只是GMM用了很多很小的model ,而DNN则用了一个很大的model

DNN把所有的state通通用同一个model来做分类,会是一种比较有效率的做法,解释如下
我们拿一个hidden layer出来,然后把这个layer里所有neuron的output降维到2维得到下图,每个点的颜色对应着input a,e,i,o,u,神奇的事情发生了:降维图上这5个元音的分布跟右上角元音位置图的分布几乎是一样的
因此,DNN并不是马上就去检测发音是属于哪一个phone或哪一个state,比较lower的layer会先观察人是用什么样的方式在发这个声音,人的舌头位置应该在哪里,是高是低,是前是后;接下来的layer再根据这个结果,去决定现在的发音是属于哪一个state或哪一个phone
这些lower的layer是一个人类发音方式的detector,而所有phone的检测都share这同一组detector的结果,因此最终的这些classifier是share了同一组用来detect发音方式的参数,这就做到了模块化,同一个参数被更多的地方share,因此显得更有效率

这个时候就可以来回答Why Deep中提到的问题了
Universality Theorem告诉我们任何的continuous的function都可以用一层足够宽的neural network来实现,在90年代,这是很多人放弃做deep learning的一个原因
但是这个理论只告诉了我们可能性,却没有说明这件事的效率问题;根据上面的几个例子我们已经知道,只用一个hidden layer来描述function其实是没有效率的;当你用multi-layer,用hierarchy structure来描述function的时候,才会是比较有效率的

下面用逻辑电路和剪窗花的例子来更形象地描述Deep和shallow的区别
逻辑电路其实可以拿来类比神经网络
Logic circuits consists of gates;Neural network consists of neurons
A two layers of logic gates can represent any Boolean function;有一个hidden layer的network(input layer+hidden layer共两层)可以表示任何continuous function
注:逻辑门只要根据input的0、1状态和对应的output分别建立起门电路关系即可建立两级电路
实际设计电路的时候,为了节约成本,会进行多级优化,建立起hierarchy架构,如果某一个结构的逻辑门组合被频繁用到的话,其实在优化电路里,这个组合是可以被多个门电路共享的,这样用比较少的逻辑门就可以完成一个电路;在deep neural network里,践行modularization的思想,许多neuron作为子特征检测器被多个classifier所共享,本质上就是参数共享,就可以用比较少的参数就完成同样的function
比较少的参数意味着不容易overfitting,用比较少的data就可以完成同样任务
我们之前讲过这个逻辑回归的分类问题,可能会出现下面这种linear model根本就没有办法分类的问题,而当你加了hidden layer的时候,就相当于做了一个feature transformation,把原来的x1,x2转换到另外一个平面,变成x1'、x2'
你会发现,在例子中通过这个hidden layer的转换,其实就好像把原来这个平面按照对角线对折了一样,对折后两个蓝色的点就重合在了一起,这个过程跟剪窗花很像:
这样做既可以解决某些情况下难以分类的问题,又能够以比较有效率的方式充分利用data(比如高维空间上的1个点等于二维空间上的5个点,相当于1笔data发挥出5笔data的作用),deep learning是更有效率的利用data
下面举了一个小例子:
左边的图是training data,右边则是1层hidden layer与3层hidden layer的不同network的情况对比,这里已经控制它们的参数数量趋于相同,试验结果是,当training data为10w笔的时候,两个network学到的样子是比较接近原图的,而如果只给2w笔training data,1层hidden layer的情况就完全崩掉了,而3层hidden layer的情况会比较好一些,它其实可以被看作是剪窗花的时候一不小心剪坏了,然后展开得到的结果
注:关于如何得到model学到的图形,可以用固定model的参数,然后对input进行梯度下降,最终得到结果,具体方法见前几章

所谓的End-to-end learning,指的是只给model input和output,而不告诉它中间每一个function要怎么分工,让它自己去学会知道在生产线的每一站,自己应该要做什么事情;在DNN里,就是叠一个很深的neural network,每一层layer就是生产线上的一个站
End-to-end Learning在语音识别上体现的非常明显
在传统的Speech Recognition里,只有最后GMM这个蓝色的block,才是由training data学出来的,前面绿色的生产线部分都是由过去的“古圣先贤”手动制订出来的,其实制订的这些function非常非常的强,可以说是增一分则太肥,减一分则太瘦这样子,以至于在这个阶段卡了将近20年
后来有了deep learning,我们就可以用neural network把DCT取代掉,甚至你从spectrogram开始都拿deep neural network取代掉,也可以得到更好的结果,如果你分析DNN的weight,它其实可以自动学到要做filter bank这件事情(filter bank是模拟人类的听觉器官所制定出来的filter)

那能不能够叠一个很深很深的neural network,input直接就是time domain上的声音信号,而output直接就是 文字,中间完全不要做Fourier transform之类。目前的结果是,它学到的极限也只是做到与做了Fourier transform的结果打平而已。Fourier transform很强,但是已经是信号处理的极限了,machine做的事情就很像是在做Fourier transform,但是只能做到一样好,没有办法做到更好
有关End-to-end Learning在Image Recognition的应用和Speech Recognition很像,这里不再赘述
那deep learning还有什么好处呢?
有时候我们会遇到非常复杂的task:
有时候非常像的input,它会有很不一样的output
比如在做图像辨识的时候,下图这个白色的狗跟北极熊其实看起来是很像的,但是你的machine要有能力知道,看到左边这张图要output狗,看到右边这张图要output北极熊
有时候看起来很不一样的input,output其实是一样的
比如下面这两个方向上看到的火车,横看成岭侧成峰,尽管看到的很不一样,但是你的machine要有能力知道这两个都是同一种东西

如果你的network只有一层的话,就只能做简单的transform,没有办法把一样的东西变得很不一样,把不一样的东西变得很像;如果要实现这些,就需要做很多层次的转换
以语音识别为例,把MFCC投影到二维平面,不同颜色代表不同人说的同一句话,第一个隐藏层输出还是很不一样,第八个隐藏层输出,不同人说的同样的句子,变得很像,经过很多的隐藏层转换后,就把他们map在一起了。


这里以MNIST手写数字识别为例,展示一下DNN中,在高维空间上对这些Complex Task的处理能力
如果把28*28个pixel组成的vector投影到二维平面上就像左上角所示,你会发现4跟9的pixel几乎是叠在一起的,因为4跟9很像,都是一个圈圈再加一条线,所以如果你光看input的pixel的话,4跟9几乎是叠在一起的,你几乎没有办法把它分开
但是,等到第二个、第三个layer的output,你会发现4、7、9逐渐就被分开了,所以使用deep learning的deep,这也是其中一个理由

Do Deep Nets Really Need To Be Deep? (by Rich Caruana)
http://research.microsoft.com/apps/video/default.aspx?id=232373&r=1
Deep Learning: Theoretical Motivations (Yoshua Bengio)
http://videolectures.net/deeplearning2015_bengio_theoretical_motivations/
Connections between physics and deep learning
https://www.youtube.com/watch?v=5MdSE-N0bxs
Why Deep Learning Works: Perspectives from Theoretical Chemistry
https://www.youtube.com/watch?v=kIbKHIPbxiU
CNN常常被用在影像处理上,它的theory base就是三个property,和两个架构 convolution 架构:针对property 1和property 2 max pooling架构:针对property 3
人们常常会说,deep learning就是一个黑盒子,你learn完以后根本就不知道它得到了什么,所以会有很多人不喜欢这种方法,这篇文章就讲述了三个问题:What does CNN do?Why CNN?How to design CNN?
我们当然可以用一般的neural network来做影像处理,不一定要用CNN,比如说,你想要做图像的分类,那你就去train一个neural network,它的input是一张图片,你就用里面的pixel来表示这张图片,也就是一个很长很长的vector,而output则是由图像类别组成的vector,假设你有1000个类别,那output就有1000个dimension
但是,我们现在会遇到的问题是这样子:实际上,在train neural network的时候,我们会有一种期待说,在这个network structure里面的每一个neuron,都应该代表了一个最基本的classifier;事实上,在文献上,根据训练的结果,也有很多人得到这样的结论,举例来说,下图中:
那现在的问题是这样子:当我们直接用一般的fully connected的feedforward network来做图像处理的时候,往往会需要太多的参数
举例来说,假设这是一张100*100的彩色图片,它的分辨率才100*100,那这已经是很小张的image了,然后你需要把它拉成一个vector,总共有100*100*3个pixel(如果是彩色的图的话,每个pixel其实需要3个value,即RGB值来描述它的),把这些加起来input vectot就已经有三万维了;如果input vector是三万维,又假设hidden layer有1000个neuron,那仅仅是第一层hidden layer的参数就已经有30000*1000个了,这样就太多了
所以,CNN做的事情其实是,来简化这个neural network的架构,我们根据自己的知识和对图像处理的理解,一开始就把某些实际上用不到的参数给过滤掉,我们一开始就想一些办法,不要用fully connected network,而是用比较少的参数,来做图像处理这件事情,所以CNN其实是比一般的DNN还要更简单的
虽然CNN看起来,它的运作比较复杂,但事实上,它的模型比DNN还要更简单,我们就是用prior knowledge,去把原来fully connected的layer里面的一些参数拿掉,就变成CNN
为什么我们有可能把一些参数拿掉?为什么我们有可能只用比较少的参数就可以来做图像处理这件事情?下面列出三个对影像处理的观察:(这也是CNN架构提出的基础所在)
在影像处理里面,如果在network的第一层hidden layer里,那些neuron要做的事情是侦测有没有一种东西、一种pattern(图案样式)出现,那大部分的pattern其实是比整张image要小的,所以对一个neuron来说,想要侦测有没有某一个pattern出现,它其实并不需要看整张image,只需要看这张image的一小部分,就可以决定这件事情了
举例来说,假设现在我们有一张鸟的图片,那第一层hidden layer的某一个neuron的工作是,检测有没有鸟嘴的存在(你可能还有一些neuron侦测有没有鸟嘴的存在、有一些neuron侦测有没有爪子的存在、有一些neuron侦测有没有翅膀的存在、有没有尾巴的存在,之后合起来,就可以侦测,图片中有没有一只鸟),那它其实并不需要看整张图,因为,其实我们只要给neuron看个小的区域,它其实就可以知道说,这是不是一个鸟嘴,对人来说也是一样,只要看这个小的区域你就会知道说这是鸟嘴,所以,每一个neuron其实只要连接到一个小块的区域就好,它不需要连接到整张完整的图,因此也对应着更少的参数
同样的pattern,可能会出现在image的不同部分,但是它们有同样的形状、代表的是同样的含义,因此它们也可以用同样的neuron、同样的参数,被同一个detector检测出来
举例来说,图中分别有一个处于左上角的鸟嘴和一个处于中央的鸟嘴,但你并不需要训练两个不同的detector去专门侦测左上角有没有鸟嘴和中央有没有鸟嘴这两件事情,这样做太冗余了,我们要cost down(降低成本),我们并不需要有两个neuron、两组不同的参数来做duplicate(重复一样)的事情,所以我们可以要求这些功能几乎一致的neuron共用一组参数,它们share同一组参数就可以帮助减少总参数的量
我们可以对一张image做subsampling(二次抽样),假如你把它奇数行、偶数列的pixel拿掉,image就可以变成原来的十分之一大小,而且并不会影响人对这张image的理解,对你来说,下面两张大小不一的image看起来不会有什么太大的区别,你都可以识别里面有什么物件,因此subsampling对图像辨识来说,可能是没有太大的影响的
所以,我们可以利用subsampling这个概念把image变小,从而减少需要用到的参数量
整个CNN的架构是这样的:
首先,input一张image以后,它会先通过Convolution的layer,接下来做Max Pooling这件事,然后再去做Convolution,再做Maxi Pooling...,这个process可以反复进行多次(重复次数需要事先决定),这就是network的架构,就好像network有几层一样,你要做几次convolution,做几次Max Pooling,在定这个network的架构时就要事先决定好
当你做完先前决定的convolution和max pooling的次数后,你要做的事情是Flatten,做完flatten以后,你就把Flatten output丢到一般的Fully connected network里面去,最终得到影像辨识的结果

我们基于之前提到的三个对影像处理的观察,设计了CNN这样的架构,第一个是要侦测一个pattern,你不需要看整张image,只要看image的一个小部分;第二个是同样的pattern会出现在一张图片的不同区域;第三个是我们可以对整张image做subsampling
那前面这两个property,是用convolution的layer来处理的;最后这个property,是用max pooling来处理的
假设现在我们network的input是一张6*6的image,图像是黑白的,因此每个pixel只需要用一个value来表示,而在convolution layer里面,有一堆Filter,这边的每一个Filter,其实就等同于是Fully connected layer里的一个neuron
每一个Filter其实就是一个matrix,这个matrix里面每一个element的值,就跟那些neuron的weight和bias一样,是network的parameter,它们具体的值都是通过Training data学出来的,而不是人去设计的
所以,每个Filter里面的值是什么,要做什么事情,都是自动学习出来的,图中每一个filter是3*3的size,意味着它就是在侦测一个3*3的pattern,当它侦测的时候,并不会去看整张image,它只看一个3*3范围内的pixel,就可以判断某一个pattern有没有出现,这就考虑了property 1
这个filter是从image的左上角开始,做一个slide window,每次向右挪动一定的距离,这个距离就叫做stride,由你自己设定,每次filter停下的时候就跟image中对应的3*3的matrix做一个内积(相同位置的值相乘并累计求和),这里假设stride=1,那么我们的filter每次移动一格,当它碰到image最右边的时候,就从下一行的最左边开始重复进行上述操作,经过一整个convolution的process,最终得到下图所示的红色的4*4 matrix

观察上图中的Filter1,它斜对角的地方是1,1,1,所以它的工作就是detect有没有连续的从左上角到右下角的1,1,1出现在这个image里面,检测到的结果已在上图中用蓝线标识出来,此时filter得到的卷积结果的左上和左下得到了最大的值,这就代表说,该filter所要侦测的pattern出现在image的左上角和左下角
同一个pattern出现在image左上角的位置和左下角的位置,并不需要用到不同的filter,我们用filter1就可以侦测出来,这就考虑了property 2
在一个convolution的layer里面,它会有一打filter,不一样的filter会有不一样的参数,但是这些filter做卷积的过程都是一模一样的,你把filter2跟image做完convolution以后,你就会得到另外一个蓝色的4*4 matrix,那这个蓝色的4*4 matrix跟之前红色的4*4matrix合起来,他们就叫做Feature Map,有多少个filter,对应就有多少个映射后的image,filter的数量等于feature map的数量

CNN对不同scale的相同pattern的处理上存在一定的困难,由于现在每一个filter size都是一样的,这意味着,如果你今天有同一个pattern,它有不同的size,有大的鸟嘴,也有小的鸟嘴,CNN并不能够自动处理这个问题;DeepMind曾经发过一篇paper,上面提到了当你input一张image的时候,它在CNN前面,再接另外一个network,这个network做的事情是,它会output一些scalar,告诉你说,它要把这个image的里面的哪些位置做旋转、缩放,然后,再丢到CNN里面,这样你其实会得到比较好的performance
刚才举的例子是黑白的image,所以你input的是一个matrix,如果今天是彩色的image会怎么样呢?我们知道彩色的image就是由RGB组成的,所以一个彩色的image,它就是好几个matrix叠在一起,是一个立方体,如果我今天要处理彩色的image,要怎么做呢?

这个时候你的filter就不再是一个matrix了,它也会是一个立方体,如果你今天是RGB这三个颜色来表示一个pixel的话,那你的input就是3*6*6,你的filter就是3*3*3,你的filter的高就是3,在做convolution的话,就是将filter的9个值和image的9个值做内积(不是把每一个channel分开来算,而是合在一起来算,一个filter就考虑了不同颜色所代表的channel)
接下来要讲的是,convolution跟fully connected有什么关系,你可能觉得说,它是一个很特别的operation,感觉跟neural network没半毛钱关系,其实,它就是一个neural network
convolution这件事情,其实就是fully connected的layer把一些weight拿掉而已,下图中绿色方框标识出的feature map的output,其实就是hidden layer的neuron的output

接下来我们来解释这件事情:
如下图所示,我们在做convolution的时候,把filter放在image的左上角,然后再去做inner product,得到一个值3;这件事情等同于,我们现在把这个image的6*6的matrix拉直变成右边这个用于input的vector,然后,你有一个neuron,这些input经过这个neuron之后,得到的output是3
那这个neuron的output怎么来的呢?这个neuron实际上就是由filter转化而来的,我们把filter放在image的左上角,此时filter考虑的就是和它重合的9个pixel,假设你把这一个6*6的image的36个pixel拉成直的vector作为input,那这9个pixel分别就对应着右侧编号1,2,3的pixel,编号7,8,9的pixel跟编号13,14,15的pixel
如果我们说这个filter和image matrix做inner product以后得到的output 3,就是input vector经过某个neuron得到的output 3的话,这就代表说存在这样一个neuron,这个neuron带weight的连线,就只连接到编号为1,2,3,7,8,9,13,14,15的这9个pixel而已,而这个neuron和这9个pixel连线上所标注的的weight就是filter matrix里面的这9个数值
作为对比,Fully connected的neuron是必须连接到所有36个input上的,但是,我们现在只用连接9个input,因为我们知道要detect一个pattern,不需要看整张image,看9个input pixel就够了,所以当我们这么做的时候,就用了比较少的参数

当我们把filter做stride = 1的移动的时候,会发生什么事呢?此时我们通过filter和image matrix的内积得到另外一个output值-1,我们假设这个-1是另外一个neuron的output,那这个neuron会连接到哪些input呢?下图中这个框起来的地方正好就对应到pixel 2,3,4,pixel 8,9,10跟pixel 14,15,16
你会发现output为3和-1的这两个neuron,它们分别去检测在image的两个不同位置上是否存在某个pattern,因此在Fully connected layer里它们做的是两件不同的事情,每一个neuron应该有自己独立的weight
但是,当我们做这个convolution的时候,首先我们把每一个neuron前面连接的weight减少了,然后我们强迫某些neuron(比如图中output为3和-1的两个neuron),它们一定要共享一组weight,虽然这两个neuron连接到的pixel对象各不相同,但它们用的weight都必须是一样的,等于filter里面的元素值,这件事情就叫做weight share,当我们做这件事情的时候,用的参数,又会比原来更少

因此我们可以这样想,有这样一些特殊的neuron,它们只连接着9条带weight的线(9=3*3对应着filter的元素个数,这些weight也就是filter内部的元素值,上图中圆圈的颜色与连线的颜色一一对应)
当filter在image matrix上移动做convolution的时候,每次移动做的事情实际上是去检测这个地方有没有某一种pattern,对于Fully connected layer来说,它是对整张image做detection的,因此每次去检测image上不同地方有没有pattern其实是不同的事情,所以这些neuron都必须连接到整张image的所有pixel上,并且不同neuron的连线上的weight都是相互独立的
那对于convolution layer来说,首先它是对image的一部分做detection的,因此它的neuron只需要连接到image的部分pixel上,对应连线所需要的weight参数就会减少;其次由于是用同一个filter去检测不同位置的pattern,所以这对convolution layer来说,其实是同一件事情,因此不同的neuron,虽然连接到的pixel对象各不相同,但是在“做同一件事情”的前提下,也就是用同一个filter的前提下,这些neuron所使用的weight参数都是相同的,通过这样一种weight share的方式,再次减少network所需要用到的weight参数
CNN的本质,就是减少参数的过程
看到这里你可能会问,这样的network该怎么搭建,又该怎么去train呢?
首先,第一件事情就是这都是用toolkit做的,所以你大概不会自己去写;如果你要自己写的话,它其实就是跟原来的Backpropagation用一模一样的做法,只是有一些weight就永远是0,你就不去train它,它就永远是0
然后,怎么让某些neuron的weight值永远都是一样呢?你就用一般的Backpropagation的方法,对每个weight都去算出gradient,再把本来要tight在一起、要share weight的那些weight的gradient平均,然后,让他们update同样值就ok了
相较于convolution,max pooling是比较简单的,它就是做subsampling,根据filter 1,我们得到一个4*4的matrix,根据filter 2,你得到另外一个4*4的matrix,接下来,我们要做什么事呢?
我们把output四个分为一组,每一组里面通过选取平均值或最大值的方式,把原来4个value合成一个 value,这件事情相当于在image每相邻的四块区域内都挑出一块来检测,这种subsampling的方式就可以让你的image缩小!

讲到这里你可能会有一个问题,如果取Maximum放到network里面,不就没法微分了吗?max这个东西,感觉是没有办法对它微分的啊,其实是可以的,后面讲到Maxout network,会告诉你怎么用微分的方式来处理它
做完一次convolution加一次max pooling,我们就把原来6*6的image,变成了一个2*2的image;至于这个2*2的image,它每一个pixel的深度,也就是每一个pixel用几个value来表示,就取决于你有几个filter,如果你有50个filter,就是50维,像下图中是两个filter,对应的深度就是两维,得到结果就是一个new image but smaller,一个filter就代表了一个channel。
所以,这是一个新的比较小的image,它表示的是不同区域上提取到的特征,实际上不同的filter检测的是该image同一区域上的不同特征属性,所以每一层channel(通道)代表的是一种属性,一块区域有几种不同的属性,就有几层不同的channel,对应的就会有几个不同的filter对其进行convolution操作,Each filter is a channel

这件事情可以repeat很多次,你可以把得到的这个比较小的image,再次进行convolution和max pooling的操作,得到一个更小的image,依次类推
有这样一个问题:假设我第一个convolution有25个filter,通过这些filter得到25个feature map,然后repeat的时候第二个convolution也有25个filter,那这样做完,我是不是会得到25^2个feature map?
其实不是这样的,你这边做完一次convolution,得到25个feature map之后再做一次convolution,还是会得到25个feature map,因为convolution在考虑input的时候,是会考虑深度的,它并不是每一个channel分开考虑,而是一次考虑所有的channel,所以,你convolution这边有多少个filter,再次output的时候就会有多少个channel,The number of the channel is the number of filters,只不过下一次convolution时,25个filter都是一个立方体,它的高有25个value那么高
这件事可以repeat很多次,通过一个convolution + max pooling就得到新的 image。它是一个比较小的image,可以把这个小的image,做同样的事情,再次通过convolution + max pooling,将得到一个更小的image。
在第一个convolution里面,每一个filter都有9个参数,它就是一个3*3的matrix;但是在第二个convolution layer里面,虽然每一个filter都是3*3,但它其实不是3*3个参数,因为它的input是一个25*13*13的cubic,这个cubic的channel有25个,所以要用同样高度的cubic filter对它进行卷积,于是我们的filter实际上是一个25*3*3的cubic,所以第二个convolution layer这边每个filter共有225个参数
通过两次convolution和max pooling的组合,最终的image变成了50*5*5的size,然后使用Flatten将这个image拉直,变成一个1250维的vector,再把它丢到一个Fully Connected Feedforward network里面,network structure就搭建完成了
看到这里,你可能会有一个疑惑,第二次convolution的input是25*13*13的cubic,用50个3*3的filter卷积后,得到的输出时应该是50个cubic,且每个cubic的尺寸为25*11*11,那么max pooling把长宽各砍掉一半后就是50层25*5*5的cubic,那flatten后不应该就是50*25*5*5吗?
其实不是这样的,在第二次做convolution的时候,我们是用25*3*3的cubic filter对25*13*13的cubic input进行卷积操作的,filter的每一层和input cubic中对应的每一层(也就是每一个channel),它们进行内积后,还要把cubic的25个channel的内积值进行求和,作为这个“neuron”的output,它是一个scalar,这个cubic filter对整个cubic input做完一遍卷积操作后,得到的是一层scalar,然后有50个cubic filter,对应着50层scalar,因此最终得到的output是一个50*11*11的cubic!
这里的关键是filter和image都是cubic,每个cubic filter有25层高,它和同样有25层高的cubic image做卷积,并不是单单把每个cubic对应的channel进行内积,还会把这些内积求和!最终变为1层,因此两个矩阵或者tensor做了卷积后,不管之前的维数如何,都会变为一个scalor!,故如果有50个Filter,无论input是什么样子的,最终的output还会是50层
做完convolution和max pooling之后,就是FLatten和Fully connected Feedforward network的部分
Flatten的意思是,把左边的feature map拉直,然后把它丢进一个Fully connected Feedforward network,然后就结束了,也就是说,我们之前通过CNN提取出了image的feature,它相较于原先一整个image的vetor,少了很大一部分内容,因此需要的参数也大幅度地减少了,但最终,也还是要丢到一个Fully connected的network中去做最后的分类工作

如果今天有一个方法,它可以让你轻易地理解为什么这个方法会下这样的判断和决策的话,那其实你会觉得它不够intelligent;它必须要是你无法理解的东西,这样它才够intelligent,至少你会感觉它很intelligent
所以,大家常说deep learning就是一个黑盒子,你learn出来以后,根本就不知道为什么是这样子,于是你会感觉它很intelligent,但是其实还是有很多方法可以分析的,今天我们就来示范一下怎么分析CNN,看一下它到底学到了什么
要分析第一个convolution的filter是比较容易的,因为第一个convolution layer里面,每一个filter就是一个3*3的matrix,它对应到3*3范围内的9个pixel,所以你只要看这个filter的值,就可以知道它在detect什么东西,因此第一层的filter是很容易理解的
但是你比较没有办法想像它在做什么事情的,是第二层的filter,它们是50个同样为3*3的filter,但是这些filter的input并不是pixel,而是做完convolution再做Max pooling的结果,因此filter考虑的范围并不是3*3=9个pixel,而是一个长宽为3*3,高为25的cubic,filter实际在image上看到的范围是远大于9个pixel的,所以你就算把它的weight拿出来,也不知道它在做什么
那我们怎么来分析一个filter它做的事情是什么呢?你可以这样做:
我们知道在第二个convolution layer里面的50个filter,每一个filter的output就是一个11*11的matrix,假设我们现在把第k个filter的output拿出来,如下图所示,这个matrix里的每一个element,我们叫它,上标k表示这是第k个filter,下标ij表示它在这个matrix里的第i个row,第j个column

接下来我们define一个叫做Degree of the activation of the k-th filter,这个值表示现在的第k个filter,它有多被activate,有多被“启动”,直观来讲就是描述现在input的东西跟第k个filter有多接近,它对filter的激活程度有多少
第k个filter被启动的degree 就定义成,它与input进行卷积所输出的output里所有element的summation,以上图为例,就是这11*11的output matrix里所有元素之和,用公式描述如下:
也就是说,我们input一张image,然后把这个filter和image进行卷积所output的11*11个值全部加起来,当作现在这个filter被activate的程度
接下来我们要做的事情是这样子,我们想要知道第k个filter的作用是什么,那我们就要找一张image,这张image可以让第k个filter被activate的程度最大;于是我们现在要解的问题是,找一个image x,它可以让我们定义的activation的degree 最大,即:
之前我们求minimize用的是gradient descent,那现在我们求Maximum用gradient ascent(梯度上升法)就可以做到这件事了
仔细一想这个方法还是颇为神妙的,因为我们现在是把input x作为要找的参数,对它去用gradient descent或ascent进行update,原来在train CNN的时候,input是固定的,model的参数是要用gradient descent去找出来的;但是现在这个立场是反过来的,在这个task里面model的参数是固定的,我们要用gradient ascent去update这个x,让它可以使degree of activation最大

上图就是得到的结果,50个filter理论上可以分别找50张image使对应的activation最大,这里仅挑选了其中的12张image作为展示,这些image有一个共同的特征,它们里面都是一些反复出现的某种texture(纹路),比如说第三张image上布满了小小的斜条纹,这意味着第三个filter的工作就是detect图上有没有斜条纹,要知道现在每个filter检测的都只是图上一个小小的范围而已,所以图中一旦出现一个小小的斜条纹,这个filter就会被activate,相应的output也会比较大,所以如果整张image上布满这种斜条纹的话,这个时候它会最兴奋,filter的activation程度是最大的,相应的output值也会达到最大
因此每个filter的工作就是去detect某一种pattern,detect某一种线条,上图所示的filter所detect的就是不同角度的线条,所以今天input有不同线条的话,某一个filter会去找到让它兴奋度最高的匹配对象,这个时候它的output就是最大的
我们做完convolution和max pooling之后,会将结果用Flatten展开,然后丢到Fully connected的neural network里面去,之前已经搞清楚了filter是做什么的,那我们也想要知道在这个neural network里的每一个neuron是做什么的,所以就对刚才的做法如法炮制

我们定义第j个neuron的output就是,接下来就用gradient ascent的方法去找一张image x,把它丢到neural network里面就可以让的值被maximize,即:
找到的结果如上图所示,同理这里仅取出其中的9张image作为展示,你会发现这9张图跟之前filter所观察到的情形是很不一样的,刚才我们观察到的是类似纹路的东西,那是因为每个filter考虑的只是图上一部分的vision,所以它detect的是一种texture;但是在做完Flatten以后,每一个neuron不再是只看整张图的一小部分,它现在的工作是看整张图,所以对每一个neuron来说,让它最兴奋的、activation最大的image,不再是texture,而是一个完整的图形,虽然它侦测的不是完整的数字,但是是比较大的pattern。
接下来我们考虑的是CNN的output,由于是手写数字识别的demo,因此这里的output就是10维,我们把某一维拿出来,然后同样去找一张image x,使这个维度的output值最大,即
你可以想象说,既然现在每一个output的每一个dimension就对应到一个数字,那如果我们去找一张image x,它可以让对应到数字1的那个output layer的neuron的output值最大,那这张image显然应该看起来会像是数字1,你甚至可以期待,搞不好用这个方法就可以让machine自动画出数字
但实际上,我们得到的结果是这样子,如下图所示

上面的每一张图分别对应着数字0-8,你会发现,可以让数字1对应neuron的output值最大的image其实长得一点也不像1,就像是电视机坏掉的样子,为了验证程序有没有bug,这里又做了一个实验,把上述得到的image真的作为testing data丢到CNN里面,结果classify的结果确实还是认为这些image就对应着数字0-8
所以今天这个neural network,它所学到的东西跟我们人类一般的想象认知是不一样的
那我们有没有办法,让上面这个图看起来更像数字呢?想法是这样的,我们知道一张图是不是一个数字,它会有一些基本的假设,比如这些image,你不知道它是什么数字,你也会认为它显然就不是一个digit,因为人类手写出来的东西就不是长这个样子的,所以我们要对这个x做一些regularization,我们要对找出来的x做一些constraint(限制约束),我们应该告诉machine说,虽然有一些x可以让你的y很大,但是它们不是数字
那我们应该加上什么样的constraint呢?最简单的想法是说,画图的时候,白色代表的是有墨水、有笔画的地方,而对于一个digit来说,整张image上涂白的区域是有限的,像上面这些整张图都是白白的,它一定不会是数字
假设image里的每一个pixel都用表示,我们把所有pixel值取绝对值并求和,也就是,这一项其实就是之前提到过的L1的regularization,再用减去这一项,得到
这次我们希望再找一个input x,它可以让最大的同时,也要让的summation越小越好,也就是说我们希望找出来的image,大部分的地方是没有涂颜色的,只有少数数字笔画在的地方才有颜色出现
加上这个constraint以后,得到的结果会像下图右侧所示一样,已经隐约有些可以看出来是数字的形状了

如果再加上一些额外的constraint,比如你希望相邻的pixel是同样的颜色等等,你应该可以得到更好的结果
其实,这就是Deep Dream的精神,Deep Dream是说,如果你给machine一张image,它会在这个image里面加上它看到的东西
怎么做这件事情呢?你就找一张image丢到CNN里面去,然后你把某一个convolution layer里面的filter或是fully connected layer里的某一个hidden layer的output拿出来,它其实是一个vector;接下来把本来是positive的dimension值调大,negative的dimension值调小,也就是让正的更正,负的更负,然后把它作为新的image的目标
这里就是把3.9、2.3的值调大,-1.5的值调小,总体来说就是使它们的绝对值变大,然后用gradient descent的方法找一张image x,让它通过这个hidden layer后的output就是你调整后的target,这么做的目的就是,让CNN夸大化它看到的东西——make CNN exaggerates what is sees
也就是说,如果某个filter有被activate,那你让它被activate的更剧烈,CNN可能本来看到了某一样东西,那现在你就让它看起来更像原来看到的东西,这就是所谓的夸大化
如果你把上面这张image拿去做Deep Dream的话,你看到的结果就会像下面这个样子
就好像背后有很多念兽,要凝才看得到,比如像上图右侧那一只熊,它原来是一个石头,对机器来说,它看这张图的时候,本来就觉得这个石头有点像熊,所以你就更强化这件事,让它看起来真的就变成了一只熊,这个就是Deep Dream
Deep Dream还有一个进阶的版本,就叫做Deep Style,如果今天你input一张image,Deep Style做的事情就是让machine去修改这张图,让它有另外一张图的风格,如下所示
实际上机器做出来的效果惊人的好,具体的做法参考reference:A Neural Algorithm of Artistic Style
这里仅讲述Deep Style的大致思路,你把原来的image丢给CNN,得到CNN filter的output,代表这样image里面有什么样的content,然后你把呐喊这张图也丢到CNN里面得到filter的output,注意,我们并不在于一个filter output的value到底是什么,一个单独的数字并不能代表任何的问题,我们真正在意的是,filter和filter的output之间的correlation,这个correlation代表了一张image的style

接下来你就再用一个CNN去找一张image,这张image的content像左边的图片,比如这张image的filter output的value像左边的图片;同时让这张image的style像右边的图片,所谓的style像右边的图片是说,这张image output的filter之间的correlation像右边这张图片
最终你用gradient descent找到一张image,同时可以maximize左边的content和右边的style,它的样子就像上图左下角所示
CNN可以被运用到不同的应用上,不只是影像处理,比如出名的alphaGo
想要让machine来下围棋,不见得要用CNN,其实一般typical的neural network也可以帮我们做到这件事情
你只要learn一个network,也就是找一个function,它的input是棋盘当前局势,output是你下一步根据这个棋盘的盘势而应该落子的位置,这样其实就可以让machine学会下围棋了,所以用fully connected的feedforward network也可以做到让machine下围棋这件事情
也就是说,你只要告诉它input是一个19*19的vector,vector的每一个dimension对应到棋盘上的某一个位置,如果那一个位置有一个黑子的话,就是1,如果有一个白子的话,就是-1,反之呢,就是0,所以如果你把棋盘描述成一个19*19的vector,丢到一个fully connected的feedforward network里,output也是19*19个dimension ,每一个dimension对应到棋盘上的一个位置,那machine就可以学会下围棋了
但实际上如果我们采用CNN的话,会得到更好的performance,我们之前举的例子都是把CNN用在图像上面,也就是input是一个matrix,而棋盘其实可以很自然地表示成一个19*19的matrix,那对CNN来说,就是直接把它当成一个image来看待,然后再output下一步要落子的位置,具体的training process是这样的:
你就搜集很多棋谱,比如说初手下在5之五,次手下在天元,然后再下在5之五,接下来你就告诉machine说,看到落子在5之五,CNN的output就是天元的地方是1,其他的output是0;看到5之五和天元都有子,那你的output就是5之五的地方是1,其他都是0
上面是supervised的部分,那其实呢AlphaGo还有reinforcement learning的部分,这个后面的章节会讲到
自从AlphaGo用了CNN以后,大家都觉得好像CNN应该很厉害,所以有时候如果你没有用CNN来处理问题,人家就会来问你;比如你去面试的时候,你的硕士论文里面没有用CNN来处理问题,口试的人可能不知道CNN是什么 ,但是他就会问你说为什么不用CNN呢,CNN不是比较强吗?这个时候如果你真的明白了为什么要用CNN,什么时候才要用CNN这个问题,你就可以直接给他怼回去
那什么时候我们可以用CNN呢?你要有image该有的那些特性,也就是上一篇文章开头所说的,根据观察到的三个property,我们才设计出了CNN这样的network架构:
CNN能够应用在Alpha-Go上,是因为围棋有一些特性和图像处理是很相似的
在property 1,有一些pattern是比整张image要小得多,在围棋上,可能也有同样的现象,比如下图中一个白子被3个黑子围住,如果下一个黑子落在白子下面,就可以把白子提走;只有另一个白子接在下面,它才不会被提走
那现在你只需要看这个小小的范围,就可以侦测这个白子是不是属于被叫吃的状态,你不需要看整个棋盘,才知道这件事情,所以这件事情跟image有着同样的性质;在AlphaGo里面,它第一个layer其实就是用5*5的filter,显然做这个设计的人,觉得围棋上最基本的pattern可能都是在5*5的范围内就可以被侦测出来
在property 2,同样的pattern可能会出现在不同的region,在围棋上也可能有这个现象,像这个叫吃的pattern,它可以出现在棋盘的左上角,也可以出现在右下角,它们都是叫吃,都代表了同样的意义,所以你可以用同一个detector,来处理这些在不同位置的同样的pattern
所以对围棋来说呢,它在第一个observation和第二个observation是有这个image的特性的,但是,让我们没有办法想通的地方,就是第三点
我们可以对一个image做subsampling,你拿掉奇数行、偶数列的pixel,把image变成原来的1/4的大小也不会影响你看这张图的样子,基于这个观察才有了Max pooling这个layer;但是,对围棋来说,它可以做这件事情吗?比如说,你对一个棋盘丢掉奇数行和偶数列,那它还和原来是同一个函式吗?显然不是的
如何解释在棋盘上使用Max Pooling这件事情呢?有一些人觉得说,因为AlphaGo使用了CNN,它里面有可能用了Max pooling这样的构架,所以,或许这是它的一个弱点,你要是针对这个弱点攻击它,也许就可以击败它
AlphaGo的paper内容不多,只有6页左右,它只说使用了CNN,却没有在正文里面仔细地描述它的CNN构架,但是在这篇paper长长附录里,其实是有描述neural network structure的
它是这样说的,input是一个19*19*48的image,其中19*19是棋盘的格局,对Alpha来说,每一个位置都用48个value来描述,这是因为加上了domain knowledge,它不只是描述某位置有没有白子或黑子,它还会观察这个位置是不是处于叫吃的状态等等

先用一个hidden layer对image做zero padding,也就是把原来19*19的image外围补0,让它变成一张23*23的image,然后使用k个5*5的filter对该image做convolution,stride设为1,activation function用的是ReLU,得到的output是21*21的image;接下来使用k个3*3的filter,stride设为1,activation function还是使用ReLU,...
你会发现这个AlphaGo的network structure一直在用convolution,其实根本就没有使用Max Pooling,原因并不是疏失了什么之类的,而是根据围棋的特性,我们本来就不需要在围棋的CNN里面,用Max pooling这样的构架
举这个例子是为了告诉大家:neural network架构的设计,是应用之道,存乎一心
CNN也可以用在很多其他的task里面,比如语音处理上,我们可以把一段声音表示成spectrogram,spectrogram的横轴是时间,纵轴则是这一段时间里声音的频率
下图中是一段“你好”的音频,偏红色代表这段时间里该频率的energy是比较大的,也就对应着“你”和“好”这两个字,也就是说spectrogram用颜色来描述某一个时刻不同频率的能量
我们也可以让机器把这个spectrogram就当作一张image,然后用CNN来判断说,input的这张image对应着什么样的声音信号,那通常用来判断结果的单位,比如phoneme,就是类似音标这样的单位

这边比较神奇的地方就是,当我们把一段spectrogram当作image丢到CNN里面的时候,在语音上,我们通常只考虑在frequency(频率)方向上移动的filter,我们的filter就像上图这样,是长方形的,它的宽就跟image的宽是一样的,并且filter只在Frequency即纵坐标的方向上移动,而不在时间的序列上移动
这是因为在语音里面,CNN的output后面都还会再接别的东西,比如接LSTM之类,所以你在CNN里面再考虑一次时间的information其实没有什么特别的帮助,但是为什么在频率上的filter有帮助呢?
我们用CNN的目的是为了用同一个filter把相同的pattern给detect出来,在声音讯号上,虽然男生和女生说同样的话看起来这个spectrogram是非常不一样的,但实际上他们的不同只是表现在一个频率的shift而已,男生说的“你好”跟女生说的“你好”,它们的pattern其实是一样的,比如pattern是spectrogram变化的情形,男生女生的声音的变化情况可能是一样的,它们的差别可能只是所在的频率范围不同而已,所以filter在frequency的direction上移动是有效的,在time domain上移动是没有帮助的。
所以,这又是另外一个例子,当你把CNN用在一个Application的时候呢,你永远要想一想这个Application的特性是什么,根据这个特性你再去design network的structure,才会真正在理解的基础上去解决问题
CNN也可以用在文字处理上,假设你的input是一个word sequence,你要做的事情是让machine侦测这个word sequence代表的意思是positive的还是negative的
首先你把这个word sequence里面的每一个word都用一个vector来表示,vector代表的这个word本身的semantic (语义),那如果两个word本身含义越接近的话,它们的vector在高维的空间上就越接近,这个东西就叫做word embedding

把一个sentence里面所有word的vector排在一起,它就变成了一张image,你把CNN套用到这个image上,那filter的样子就是上图蓝色的matrix,它的高和image的高是一样的,然后把filter沿着句子里词汇的顺序来移动,每个filter移动完成之后都会得到一个由内积结果组成的vector,不同的filter就会得到不同的vector,接下来做Max pooling,然后把Max pooling的结果丢到fully connected layer里面,你就会得到最后的output
与语音处理不同的是,在文字处理上,filter只在时间的序列(按照word的顺序)上移动,而不在这个embedding的dimension上移动;因为在word embedding里面,不同dimension是independent的,它们是相互独立的,不会出现有两个相同的pattern的情况,所以在这个方向上面移动filter,是没有意义的
所以这又是另外一个例子,虽然大家觉得CNN很powerful,你可以用在各个不同的地方,但是当你应用到一个新的task的时候,你要想一想这个新的task在设计CNN的构架的时候,到底该怎么做
The methods of visualization in these slides
https://blog.keras.io/how-convolutional-neural-networks-see-the-world.html
More about visualization
http://cs231n.github.io/understanding-cnn/
Very cool CNN visualization toolkit
http://scs.ryerson.ca/~aharley/vis/conv/
如果你想知道更多visualization事情的话,以上是一些reference。
PixelRNN
https://arxiv.org/abs/1601.06759
Variation Autoencoder(VAE)
https://arxiv.org/abs/1312.6114
Generative Adversarial Network(GAN)
https://arxiv.org/abs/1406.2661
如果你想要用Deep Dream的方法来让machine自动产生一个digit,这件事是不太成功的,但是有很多其它的方法,可以让machine画出非常清晰的图。这里列了几个方法,比如说:PixelRNN,VAE,GAN等进行参考。
RNN,或者说最常用的LSTM,一般用于记住之前的状态,以供后续神经网络的判断,它由input gate、forget gate、output gate和cell memory组成,每个LSTM本质上就是一个neuron,特殊之处在于有4个输入:和三门控制信号、和,每个时间点的输入都是由当前输入值+上一个时间点的输出值+上一个时间点cell值来组成
介绍了该如何训练RNN
在智能客服、智能订票系统中,往往会需要slot filling技术,它会分析用户说出的语句,将时间、地址等有效的关键词填到对应的槽上,并过滤掉无效的词语
Solving slot filling by Feedforward network?
How to represent each word as a vector?
1-of-N encoding
Beyond 1-of-N encoding
但这样做会有一个问题,句子中“arrive”和“leave”这两个词汇,它们都属于“other”,这时对NN来说,输入是相同的,它没有办法区分出“Taipei”是出发地还是目的地
这个时候我们就希望神经网络是有记忆的,如果NN在看到“Taipei”的时候,还能记住之前已经看过的“arrive”或是“leave”,就可以根据上下文得到正确的答案

这种有记忆力的神经网络,就叫做Recurrent Neural Network(RNN)
在RNN中,hidden layer每次产生的output 、,都会被存到memory里,下一次有input的时候,这些neuron就不仅会考虑新输入的、,还会考虑存放在memory中的、
注:在input之前,要先给内存里的赋初始值,比如0

注意到,每次NN的输出都要考虑memory中存储的临时值,而不同的输入产生的临时值也尽不相同,因此改变输入序列的顺序会导致最终输出结果的改变,Changing the sequence order will change the output
用RNN处理Slot Filling的流程举例如下:

注意:上图为同一个RNN在三个不同时间点被分别使用了三次,并非是三个不同的NN
这个时候,即使输入同样是“Taipei”,我们依旧可以根据前文的“leave”或“arrive”来得到不一样的输出

RNN有不同的变形:
由于hidden layer没有明确的训练目标,而整个NN具有明确的目标,y是有target的,所以可以比较清楚放在memory里面是什么样的东西。因此Jordan Network的表现会更好一些

RNN 还可以是双向的,你可以同时训练一对正向和反向的RNN,把它们对应的hidden layer 拿出来,都接给一个output layer,得到最后的
使用Bi-RNN的好处是,NN在产生输出的时候,它能够看到的范围是比较广的,RNN在产生的时候,它不只看了从句首开始到的输入,还看了从句尾一直到的输入,这就相当于RNN在看了整个句子之后,才决定每个词汇具体要被分配到哪一个槽中,这会比只看句子的前一半要更好

前文提到的RNN只是最简单的版本,并没有对memory的管理多加约束,可以随时进行读取,而现在常用的memory管理方式叫做长短期记忆(Long Short-term Memory),简称LSTM
可以被理解为比较长的短期记忆,因此是short-term,而非是long-short term
LSTM有三个gate:
整个LSTM可以看做是4个input,1个output:

如果从表达式的角度看LSTM,它比较像下图中的样子

把、、、通过activation function,分别得到、、、
其中对、和来说,它们通过的激活函数一般会选sigmoid function,因为它的输出在0~1之间,代表gate被打开的程度
令与相乘得到,然后把原先存放在cell中的与相乘得到,两者相加得到存在memory中的新值
从中也可以看出,forget gate的逻辑与我们的直觉是相反的,控制信号打开表示记得,关闭表示遗忘
此后,通过激活函数得到,与output gate的相乘,得到输出
下图演示了一个LSTM的基本过程,、、是输入序列,是输出序列,基本原则是:

你可能会觉得上面的结构与平常所见的神经网络不太一样,实际上我们只需要把LSTM整体看做是下面的一个neuron即可

假设目前我们的hidden layer只有两个neuron,则结构如下图所示:

从上图中你可能看不出LSTM与RNN有什么关系,接下来我们用另外的图来表示它
假设我们现在有一整排的LSTM作为neuron,每个LSTM的cell里都存了一个scalar值,把所有的scalar连接起来就组成了一个vector
在时间点,输入了一个vector ,它会乘上一个matrix,通过转换得到,而的每个dimension就代表了操控每个LSTM的输入值,同理经过不同的转换得到、和,得到操控每个LSTM的门信号

下图是单个LSTM的运算情景,其中LSTM的4个input分别是、、和的其中1维,每个LSTM的cell所得到的input都是各不相同的,但它们却是可以一起共同运算的,整个运算流程如下图左侧所示:
与上一个时间点的cell值相乘,并加到经过input gate的输入上,得到这个时刻cell中的值,最终再乘上output gate的信号,得到输出

上述的过程反复进行下去,就得到下图中各个时间点上,LSTM值的变化情况,其中与上面的描述略有不同的是,这里还需要把hidden layer的最终输出以及当前cell的值都连接到下一个时间点的输入上
因此在下一个时间点操控这些gate值,不只是看输入的,还要看前一个时间点的输出和cell值,你需要把、和这3个vector并在一起,乘上4个不同的转换矩阵,去得到LSTM的4个输入值、、、,再去对LSTM进行操控
注意:下图是同一个LSTM在两个相邻时间点上的情况

上图是单个LSTM作为neuron的情况,事实上LSTM基本上都会叠多层,如下图所示,左边两个LSTM代表了两层叠加,右边两个则是它们在下一个时间点的状态

依旧是Slot Filling的例子,我们需要把model的输出与映射到slot的reference vector求交叉熵,比如“Taipei”对应到的是“dest”这个slot,则reference vector在“dest”位置上值为1,其余维度值为0
RNN的output和reference vector的cross entropy之和就是损失函数,也是要minimize的对象
需要注意的是,word要依次输入model,比如“arrive”必须要在“Taipei”前输入,不能打乱语序

有了损失函数后,训练其实也是用梯度下降法,为了计算方便,这里采取了反向传播(Backpropagation)的进阶版,Backpropagation through time,简称BPTT算法
BPTT算法与BP算法非常类似,只是多了一些时间维度上的信息,这里不做详细介绍

不幸的是,RNN的训练并没有那么容易
我们希望随着epoch的增加,参数的更新,loss应该要像下图的蓝色曲线一样慢慢下降,但在训练RNN的时候,你可能会遇到类似绿色曲线一样的学习曲线,loss剧烈抖动,并且会在某个时刻跳到无穷大,导致程序运行失败

分析可知,RNN的error surface,即loss由于参数产生的变化,是非常陡峭崎岖的
下图中,轴代表loss,轴和轴代表两个参数和,可以看到loss在某些地方非常平坦,在某些地方又非常的陡峭
如果此时你的训练过程类似下图中从下往上的橙色的点,它先经过一块平坦的区域,又由于参数的细微变化跳上了悬崖,这就会导致loss上下抖动得非常剧烈
如果你的运气特别不好,一脚踩在悬崖上,由于之前一直处于平坦区域,gradient很小,你会把参数更新的步长(learning rate)调的比较大,而踩到悬崖上导致gradient突然变得很大,这会导致参数一下子被更新了一个大步伐,导致整个就飞出去了,这就是学习曲线突然跳到无穷大的原因

想要解决这个问题,就要采用Clipping方法,当gradient即将大于某个threshold的时候,就让它停止增长,比如当gradient大于15的时候就直接让它等于15
为什么RNN会有这种奇特的特性呢?下图给出了一个直观的解释:
假设RNN只含1个neuron,它是linear的,input和output的weight都是1,没有bias,从当前时刻的memory值接到下一时刻的input的weight是,按照时间点顺序输入[1, 0, 0, 0, ..., 0]
当第1个时间点输入1的时候,在第1000个时间点,RNN输出的,想要知道参数的梯度,只需要改变的值,观察对RNN的输出有多大的影响即可:

因此我们可以解释,RNN训练困难,是由于它把同样的操作在不断的时间转换中重复使用
从memory接到neuron输入的参数,在不同的时间点被反复使用,的变化有时候可能对RNN的输出没有影响,而一旦产生影响,经过长时间的不断累积,该影响就会被放得无限大,因此RNN经常会遇到这两个问题:
有什么技巧可以帮我们解决这个问题呢?LSTM就是最广泛使用的技巧,它会把error surface上那些比较平坦的地方拿掉,从而解决梯度消失(gradient vanishing)的问题,但它无法处理梯度崎岖的部分,因而也就无法解决梯度爆炸的问题(gradient explode)
但由于做LSTM的时候,大部分地方的梯度变化都很剧烈,因此训练时可以放心地把learning rate设的小一些
Q:为什么要把RNN换成LSTM?
A:LSTM可以解决梯度消失的问题
Q:为什么LSTM能够解决梯度消失的问题?
A:RNN和LSTM对memory的处理其实是不一样的:
对RNN来说,对memory的影响每次都会被清除,而对LSTM来说,除非forget gate被打开,否则对memory的影响就不会被清除,而是一直累加保留,因此它不会有梯度消失的问题

另一个版本GRU (Gated Recurrent Unit),只有两个gate,需要的参数量比LSTM少,鲁棒性比LSTM好,不容易过拟合,它的基本精神是旧的不去,新的不来,GRU会把input gate和forget gate连起来,当forget gate把memory里的值清空时,input gate才会打开,再放入新的值
此外,还有很多技术可以用来处理梯度消失的问题,比如Clockwise RNN、SCRN等

在Slot Filling中,我们输入一个word vector输出它的label,除此之外RNN还可以做更复杂的事情
Many to one:Input is a vector sequence, but output is only one vector
语义情绪分析,我们可以把某影片相关的文章爬下来,并分析其正面情绪or负面情绪
RNN的输入是字符序列,在不同时间点输入不同的字符,并在最后一个时间点把hidden layer 拿出来,再经过一系列转换,可以得到该文章的语义情绪的prediction
Many to one:Both input and output are both sequences, but the output is shorter.
关键词分析,RNN可以分析一篇文章并提取出其中的关键词,这里需要把含有关键词标签的文章作为RNN的训练数据

Many to Many (Output is shorter):Both input and output are both sequences, but the output is shorter.
以语音识别为例,输入是一段声音信号,每隔一小段时间就用1个vector来表示,因此输入为vector sequence,而输出则是character sequence
如果依旧使用Slot Filling的方法,只能做到每个vector对应1个输出的character,识别结果就像是下图中的“好好好棒棒棒棒棒”,但这不是我们想要的,可以使用Trimming的技术把重复内容消去,剩下“好棒”

但“好棒”和“好棒棒”实际上是不一样的,如何区分呢?
需要用到CTC算法,它的基本思想是,输出不只是字符,还要填充NULL,输出的时候去掉NULL就可以得到叠字的效果

下图是CTC的示例,RNN的输出就是英文字母+NULL,google的语音识别系统据说就是用CTC实现的

Many to Many (No Limitation):Both input and output are both sequences with different lengths.
在CTC中,input比较长,output比较短;而在Seq2Seq中,并不确定谁长谁短
比如现在要做机器翻译,将英文的word sequence翻译成中文的character sequence
假设在两个时间点分别输入“machine”和“learning”,则在最后1个时间点memory就存了整个句子的信息,接下来让RNN输出,就会得到“机”,把“机”当做input,并读取memory里的值,就会输出“器”,依次类推,这个RNN甚至会一直输出,不知道什么时候会停止

怎样才能让机器停止输出呢?
可以多加一个叫做“断”的symbol “===”,当输出到这个symbol时,机器就停止输出

具体的处理技巧这里不再详述
一种语言的声音讯号翻译成另一种语言的文字,很神奇的可以work

Sequence-to-sequence还可以用在句法解析上,让机器看一个句子,它可以自动生成树状的语法结构图

如果用bag-of-word来表示一篇文章,就很容易丢失词语之间的联系,丢失语序上的信息
比如“白血球消灭了感染病”和“感染病消灭了白血球”,两者bag-of-word是相同的,但语义却是完全相反的

这里就可以使用Sequence-to-sequence Auto-encoder,在考虑了语序的情况下,把文章编码成vector,只需要把RNN当做编码器和解码器即可
我们输入word sequence,通过RNN变成embedded vector,再通过另一个RNN解压回去,如果能够得到一模一样的句子,则压缩后的vector就代表了这篇文章中最重要的信息

这个结构甚至可以被层次化,我们可以对句子的几个部分分别做vector的转换,最后合并起来得到整个句子的vector

Sequence-to-sequence Auto-encoder还可以用在语音处理上,它可以把一段语音信号编码成vector

这种方法可以把声音信号都转化为低维的vector,并通过计算相似度来做语音搜索

如何把audio segment变成vector呢?先把声音信号转化成声学特征向量(acoustic features),再通过RNN编码,最后一个时间点存在memory里的值就代表了整个声音信号的信息

为了能够对该神经网络训练,还需要一个RNN作为解码器,得到还原后的,使之与的差距最小

最后得到vector的可视化

除了RNN之外,Attention-based Model也用到了memory的思想
机器会有自己的记忆池,神经网络通过操控读写头去读或者写指定位置的信息,这个过程跟图灵机很像,因此也被称为neural turing machine

这种方法通常用在阅读理解上,让机器读一篇文章,再把每句话的语义都存到不同的vector中,接下来让用户向机器提问,神经网络就会去调用读写头的中央处理器,取出memory中与查询语句相关的信息,综合处理之后,可以给出正确的回答
半监督学习(semi-supervised learning) 1、introduction 2、Semi-supervised Learning for Generative Model 3、Low-density Separation Assumption:非黑即白 4、Smoothness Assumption:近朱者赤,近墨者黑 5、Better Representation:去芜存菁,化繁为简
Supervised Learning:
Semi-supervised Learning:} +
training data中,部分data没有标签,只有input ,没有output
通常遇到的场景是,无标签的数据量远大于有标签的数据量,即U>>R
semi-supervised learning分为以下两种情况:
Transductive Learning:unlabeled data is the testing data
即,把testing data当做无标签的training data使用,适用于事先已经知道testing data的情况(一些比赛的时候)
值得注意的是,这种方法使用的仅仅是testing data的feature,而不是label,因此不会出现“直接对testing data做训练而产生cheating的效果”
Inductive Learning:unlabeled data is not the testing data
即,不把testing data的feature拿去给机器训练,适用于事先并不知道testing data的情况(更普遍的情况)
为什么要做semi-supervised learning?
实际上我们从来不缺data,只是缺有label的data,就像你可以拍很多照片,但它们一开始都是没有标签的
为什么semi-supervised learning会有效呢?
The distribution of the unlabeled data tell us something.
unlabeled data虽然只有input,但它的分布,却可以告诉我们一些事情
以下图为例,在只有labeled data的情况下,红线是二元分类的分界线

但当我们加入unlabeled data的时候,由于特征分布发生了变化,分界线也随之改变

semi-supervised learning的使用往往伴随着假设,而该假设的合理与否,决定了结果的好坏程度;比如上图中的unlabeled data,它显然是一只狗,而特征分布却与猫被划分在了一起,很可能是由于这两张图片的背景都是绿色导致的,因此假设是否合理显得至关重要
事实上,在监督学习中,我们已经讨论过概率生成模型了,假设class1和class2的分布分别为、的高斯分布,计算出Prior Probability后,再根据贝叶斯公式可以推得新生成的x所属的类别

如果在原先的数据下多了unlabeled data(下图中绿色的点),它就会影响最终的决定,你会发现原先的显然是不合理的,新的需要使得样本点的分布更接近下图虚线圆所标出的范围,除此之外,右侧的Prior Probability会给人一种比左侧大的感觉(右侧样本点"变多"了)
此时,unlabeled data对都产生了一定程度的影响,划分两个class的decision boundary也会随之发生变化

讲完了直观上的解释,接下来进行具体推导(假设做二元分类):
先随机初始化一组参数:
step1:利用初始model计算每一笔unlabeled data 属于class 1的posterior probability
step2:update model
如果不考虑unlabeled data,则先验概率显然为属于class1的样本点数/总的样本点数,即
而考虑unlabeled data时,分子还要加上所有unlabeled data属于class 1的概率和,此时它们被看作小数,可以理解为按照概率一部分属于,一部分属于
同理,对于均值,原先的mean 加上根据概率对求和再归一化的结果即可
剩余的参数同理,接下来就有了一组新的参数,于是回到step1->step2->step1循环
理论上该方法保证是可以收敛的,而一开始给的初始值会影响收敛的结果,类似gradient descent
上述的step1就是EM algorithm里的E,step2则是M
以上的推导基于的基本思想是,把unlabeled data 看成是可以划分的,一部分属于,一部分属于,此时它的概率,也就是的先验概率乘上这个class产生的概率+的先验概率乘上这个class产生的概率
实际上我们在利用极大似然函数更新参数的时候,就利用了该拆分的结果:

接下来介绍一种新的方法,它基于的假设是Low-density separation
通俗来讲,就是这个世界是非黑即白的,在两个class的交界处data的密度(density)是很低的,它们之间会有一道明显的鸿沟,此时unlabeled data(下图绿色的点)就是帮助你在原本正确的基础上挑一条更好的boundary

low-density separation最具代表性也最简单的方法是self training
注:该方法对Regression是不适用的
该方法与之前提到的generative model还是挺像的,区别在于:
如果我们使用的是neural network的做法,是从labeled data中得到的一组参数,此时丢进来一个unlabeled data ,通过后得到,即它有0.7的概率属于class 1,0.3的概率属于class 2
可以看到,在neural network里使用soft label是没有用的,因为把原始的model里的某个点丢回去重新训练,得到的依旧是同一组参数,实际上low density separation就是通过强制分类(hard label)来提升分类效果的方法
该方法是low-density separation的进阶版,你可能会觉得hard label这种直接强制性打标签的方式有些太武断了,而entropy-based regularization则做了相应的改进:,其中是一个概率分布(distribution)
由于我们不知道unlabeled data 的label到底是什么,但如果通过entropy-based regularization得到的分布集中在某个class上的话,那这个model就是好的,而如果分布是比较分散的,那这个model就是不好的,如下图所示:

接下来的问题是,如何用数值的方法来evaluate distribution的集中(好坏)与否,要用到的方法叫entropy,一个distribution的entropy可以告诉你它的集中程度:
对上图中的第1、2种情况,算出的,而第3种情况,算出的,可见entropy越大,distribution就越分散;entropy越小,distribution就越集中
因此我们的目标是在labeled data上分类要正确,在unlabeled data上,output的entropy要越小越好,此时就要修改loss function
对labeled data来说,它的output要跟正确的label越接近越好,用cross entropy表示如下:
对unlabeled data来说,要使得该distribution(也就是output)的entropy越小越好:
两项综合起来,可以用weight来加权,以决定哪个部分更为重要一些
可以发现该式长得很像regularization,这也就是Entropy-based Regularization的名称由来
SVM要做的是,给你两个class的data,去找一个boundary:
对unlabeled data穷举所有可能的label,下图中列举了三种可能的情况;然后对每一种可能的结果都去算SVM,再找出可以让margin最大,同时又minimize error的那种情况,下图中是用黑色方框标注的情况

Thorsten Joachims, ”Transductive Inference for Text Classification using Support Vector Machines”, ICML, 1999
当然这么做会存在一个问题,对于n笔unlabeled data,意味着即使在二元分类里也有种可能的情况,数据量大的时候,几乎难以穷举完毕,上面给出的paper提出了一种approximate的方法,基本精神是:一开始你先得到一些label,然后每次改一笔unlabeled data的label,看看可不可以让你的objective function变大,如果变大就去改变该label,具体内容详见paper
smoothness assumption的基本精神是:近朱者赤,近墨者黑
粗略的定义是相似的x具有相同的,精确的定义是:
x的分布是不平均的,在某些地方很集中,某些地方很分散
如果和在一个high density region上很接近的话,那么和就是相同的
也就是这两个点可以在样本点高密度集中分布的区域块中有一条可连接的路径,即 connected by a high density path
假设下图是data的分布,是其中的三笔data,如果单纯地看x的相似度,显然和更接近一些,但对于smoothness assumption来说,和是处于同一块区域的,它们之间可以有一条相连的路径;而与之间则是“断开”的,没有high density path,因此与更“像”

以手写数字识别为例,对于最右侧的2和3以及最左侧的2,显然最右侧的2和3在pixel上相似度更高一些;但如果把所有连续变化的2都放进来,就会产生一种“不直接相连的相似”,根据Smoothness Assumption的理论,由于2之间有连续过渡的形态,因此第一个2和最后一个2是比较像的,而最右侧2和3之间由于没有过渡的data,因此它们是比较不像的
人脸的过渡数据也同理

Smoothness Assumption在文件分类上是非常有用的
假设对天文学(astronomy)和旅行(travel)的文章进行分类,它们各自有专属的词汇,此时如果unlabeled data与label data的词汇是相同或重合(overlap)的,那么就很容易分类;但在真实的情况下,unlabeled data和labeled data之间可能没有任何重复的words,因为世界上的词汇太多了,sparse的分布很难会使overlap发生
但如果unlabeled data足够多,就会以一种相似传递的形式,建立起文档之间相似的桥梁
在具体实现上,有一种简单的方法是cluster and then label,也就是先把data分成几个cluster,划分class之后再拿去训练,但这种方法不一定会得到好的结果,因为它的假设是你可以把同一个class的样本点cluster在一起,而这其实是没那么容易的
对图像分类来说,如果单纯用pixel的相似度来划分cluster,得到的结果一般都会很差,你需要设计一个很好的方法来描述image(类似Deep Autoencoder的方式来提取feature),这样cluster才会有效果

之前讲的是比较直觉的做法,接下来引入Graph Structure来表达connected by a high density path这件事

Represented the data points as a graph,有时候建立vertex之间的关系是比较容易的,比如网页之间的链接关系、论文之间的引用关系;但有时候需要你自己去寻找vertex之间的关系,建立graph
graph的好坏,对结果起着至关重要的影响,而如何build graph却是一件heuristic的事情,需要凭着经验和直觉来做
首先定义两个object 之间的相似度
如果是基于pixel的相似度,performance可能会不太好;建议使用autoencoder提取出来的feature来计算相似度,得到的performance会好一些
算完相似度后,就可以建graph了,方式有很多种:
除此之外,还可以给Edge特定的weight,让它与相似度成正比
建议用Gaussian Radial Basis Function来确定相似度:
这里均为vector,计算它们的Euclidean Distance(欧几里得距离),乘一个参数后再取exponential
至于取exponential,经验上来说通常是可以帮助提升performance的,在这里只有当非常接近的时候,similarity才会大;只要距离稍微远一点,similarity就会下降得很快,变得很小
使用exponential的Gaussian Radial Basis Function可以做到只有非常近的两个点才能相连,稍微远一点就无法相连的效果,避免了下图中跨区域相连的情况

graph-based approach的基本精神是,在graph上已经有一些labeled data,那么跟它们相连的point,属于同一类的概率就会上升,每一笔data都会去影响它的邻居,而graph带来的最重要的好处是,这个影响是会随着edges传递出去的,即使有些点并没有真的跟labeled data相连,也可以被传递到相应的属性
比如下图右下,如果graph建的足够好,那么两个被分别label为蓝色和红色的点就可以传递完两张完整的图;从下图右上中我们也可以看出,如果想要让这种方法生效,收集到的data一定要足够多,否则可能传递到一半,graph就断掉了,information的传递就失效了

介绍完了如何定性使用graph,接下来介绍一下如何定量使用graph
定量的使用方式是定义label的smoothness,下图中,edge上的数字是weight,表达data,表示data的label,计算smoothness的方式为:
我们期望smooth的值越小越好

当然上面的式子还可以化简,如果把labeled data和unlabeled data的y组成一个(R+U)-dim vector,即
于是smooth可以改写为:
其中L为(R+U)×(R+U) matrix,成为Graph Laplacian, 定义为

对来说,y是label,是neural network的output,取决于neural network的parameters,因此要在原来仅针对labeled data的loss function中加上这一项,得到:
实际上也象征着一个regularization term
训练目标:
具体训练的时候,不一定只局限于neural network的output要smooth,可以对中间任意一个hidden layer加上smooth的限制

Better Representation的精神是,去芜存菁,化繁为简
我们观察到的世界是比较复杂的,而在它的背后其实是有一些比较简单的东西,在操控着这个复杂的世界,所以只要你能够看透这个世界的假象,直指它的核心的话,就可以让training变得比较容易
Find the latent factors behind the observation
The latent factors (usually simpler) are better representations
算法具体思路和内容unsupervised learning中介绍
本文介绍NLP中词嵌入(Word Embedding)相关的基本知识,基于降维思想提供了count-based和prediction-based两种方法,并介绍了该思想在机器问答、机器翻译、图像分类、文档嵌入等方面的应用
词嵌入(word embedding)是降维算法(Dimension Reduction)的典型应用
那如何用vector来表示一个word呢?
最传统的做法是1-of-N Encoding,假设这个vector的维数就等于世界上所有单词的数目,那么对每一个单词来说,只需要某一维为1,其余都是0即可;但这会导致任意两个vector都是不一样的,你无法建立起同类word之间的联系
还可以把有同样性质的word进行聚类(clustering),划分成多个class,然后用word所属的class来表示这个word,但光做clustering是不够的,不同class之间关联依旧无法被有效地表达出来
词嵌入(Word Embedding)把每一个word都投影到高维空间上,当然这个空间的维度要远比1-of-N Encoding的维度低,假如后者有10w维,那前者只需要50~100维就够了,这实际上也是Dimension Reduction的过程
类似语义(semantic)的词汇,在这个word embedding的投影空间上是比较接近的,而且该空间里的每一维都可能有特殊的含义
假设词嵌入的投影空间如下图所示,则横轴代表了生物与其它东西之间的区别,而纵轴则代表了会动的东西与静止的东西之间的差别

word embedding是一个无监督的方法(unsupervised approach),只要让机器阅读大量的文章,它就可以知道每一个词汇embedding之后的特征向量应该长什么样子
Machine learns the meaning of words from reading a lot of documents without supervision
我们的任务就是训练一个neural network,input是词汇,output则是它所对应的word embedding vector,实际训练的时候我们只有data的input,该如何解这类问题呢?
之前提到过一种基于神经网络的降维方法,Auto-Encoder,就是训练一个model,让它的输入等于输出,取出中间的某个隐藏层就是降维的结果,自编码的本质就是通过自我压缩和解压的过程来寻找各个维度之间的相关信息。但word embedding这个问题是不能用Auto-encoder来解的,因为输入的向量通常是1-of-N encoding,各维无关,很难通过自编码的过程提取出什么有用信息。
基本精神就是,每一个词汇的含义都可以根据它的上下文来得到
A word can be understood by its context
比如机器在两个不同的地方阅读到了“马英九宣誓就职”、“蔡英文宣誓就职”,它就会发现“马英九”和“蔡英文”前后都有类似的文字内容,于是机器就可以推测“马英九”和“蔡英文”这两个词汇代表了可能有同样地位的东西,即使它并不知道这两个词汇是人名
怎么用这个思想来找出word embedding的vector呢?有两种做法:
假如和这两个词汇常常在同一篇文章中出现(co-occur),它们的word vector分别用和来表示,则和会比较接近
假设是和这两个词汇在相同文章里同时出现的次数,我们希望它与的内积越接近越好,这个思想和之前的文章中提到的矩阵分解(matrix factorization)的思想其实是一样的
这种方法有一个很代表性的例子是Glove Vector
给定一个sentence,我们要训练一个神经网络,它要做的就是根据当前的word ,来预测下一个可能出现的word 是什么
假设我们使用1-of-N encoding把表示成feature vector,它作为neural network的input。output的维数和input相等,只不过每一维都是小数,代表在1-of-N编码中该维为1其余维为0所对应的word会是下一个word 的概率
把第一个hidden layer的input 拿出来,它们所组成的就是word的另一种表示方式,当我们input不同的词汇,向量就会发生变化
也就是说,第一层hidden layer的维数可以由我们决定,而它的input又唯一确定了一个word,因此提取出第一层hidden layer的input,实际上就得到了一组可以自定义维数的Word Embedding的向量

prediction-based方法是如何体现根据词汇的上下文来了解该词汇的含义这件事呢?
假设在两篇文章中,“蔡英文”和“马英九”代表,“宣誓就职”代表,我们希望对神经网络输入“蔡英文”或“马英九”这两个词汇,输出的vector中对应“宣誓就职”词汇的那个维度的概率值是高的
为了使这两个不同的input通过NN能得到相同的output,就必须在进入hidden layer之前,就通过weight的转换将这两个input vector投影到位置相近的低维空间上
也就是说,尽管两个input vector作为1-of-N编码看起来完全不同,但经过参数的转换,将两者都降维到某一个空间中,在这个空间里,经过转换后的new vector 1和vector 2是非常接近的,因此它们同时进入一系列的hidden layer,最终输出时得到的output是相同的
因此,词汇上下文的联系就自动被考虑在这个prediction model里面
总结一下,对1-of-N编码进行Word Embedding降维的结果就是神经网络模型第一层hidden layer的输入向量,该向量同时也考虑了上下文词汇的关联,我们可以通过控制第一层hidden layer的大小从而控制目标降维空间的维数

你可能会觉得通过当前词汇预测下一个词汇这个约束太弱了,由于不同词汇的搭配千千万万,即便是人也无法准确地给出下一个词汇具体是什么
你可以扩展这个问题,使用10个及以上的词汇去预测下一个词汇,可以帮助得到较好的结果
这里用2个词汇举例,如果是一般是神经网络,我们直接把和这两个vector拼接成一个更长的vector作为input即可
但实际上,我们希望和相连的weight与和相连的weight是tight在一起的,简单来说就是与的相同dimension对应到第一层hidden layer相同neuron之间的连线拥有相同的weight,在下图中,用同样的颜色标注相同的weight:

如果我们不这么做,那把同一个word放在的位置和放在的位置,得到的Embedding结果是会不一样的,把两组weight设置成相同,可以使与的相对位置不会对结果产生影响
除此之外,这么做还可以通过共享参数的方式有效地减少参数量,不会由于input的word数量增加而导致参数量剧增
假设的1-of-N编码为,的1-of-N编码为,维数均为,表示数据中的words总数
hidden layer的input为向量,长度为,表示降维后的维数
其中和都是维的weight matrix,它由组维的向量构成,第一组维向量与维的相乘得到,第二组维向量与维的相乘得到,...,依次类推
我们强迫让,此时
因此,只要我们得到了这组参数,就可以与1-of-N编码相乘得到word embedding的结果

那在实际操作上,我们如何保证和一样呢?
以下图中的和为例,我们希望它们的weight是一样的:
首先在训练的时候就要给它们一样的初始值
然后分别计算loss function 对和的偏微分,并对其进行更新
这个时候你就会发现,对和的偏微分是不一样的,这意味着即使给了和相同的初始值,更新过一次之后它们的值也会变得不一样,因此我们必须保证两者的更新过程是一致的,即:
这个时候,我们就保证了和始终相等:
如何去训练这个神经网络呢?注意到这个NN完全是unsupervised,你只需要上网爬一下文章数据直接喂给它即可
比如喂给NN的input是“潮水”和“退了”,希望它的output是“就”,之前提到这个NN的输出是一个由概率组成的vector,而目标“就”是只有某一维为1的1-of-N编码,我们希望minimize它们之间的cross entropy,也就是使得输出的那个vector在“就”所对应的那一维上概率最高

除了上面的基本形态,Prediction-based方法还可以有多种变形
CBOW(Continuous bag of word model)
拿前后的词汇去预测中间的词汇
Skip-gram
拿中间的词汇去预测前后的词汇

假设你有读过word vector的文献的话,你会发现这个neural network其实并不是deep的,它就只有一个linear的hidden layer
我们把1-of-N编码输入给神经网络,经过weight的转换得到Word Embedding,再通过第一层hidden layer就可以直接得到输出
其实过去有很多人使用过deep model,但这个task不用deep就可以实现,这样做既可以减少运算量,跑大量的data,又可以节省下训练的时间(deep model很可能需要长达好几天的训练时间)
从得到的word vector里,我们可以发现一些原本并不知道的word与word之间的关系

把word vector两两相减,再投影到下图中的二维平面上,如果某两个word之间有类似包含于的相同关系,它们就会被投影到同一块区域

利用这个概念,我们可以做一些简单的推论:
在word vector的特征上,
此时如果有人问“罗马之于意大利等于柏林之于?”,那机器就可以回答这个问题
因为德国的vector会很接近于“柏林的vector-罗马的vector+意大利的vector”,因此机器只需要计算,然后选取与这个结果最接近的vector即可

此外,word vector还可以建立起不同语言之间的联系
如果你要用上述方法分别训练一个英文的语料库(corpus)和中文的语料库,你会发现两者的word vector之间是没有任何关系的,因为Word Embedding只体现了上下文的关系,如果你的文章没有把中英文混合在一起使用,机器就没有办法判断中英文词汇之间的关系
但是,如果你知道某些中文词汇和英文词汇的对应关系,你可以先分别获取它们的word vector,然后再去训练一个模型,把具有相同含义的中英文词汇投影到新空间上的同一个点
接下来遇到未知的新词汇,无论是中文还是英文,你都可以采用同样的方式将其投影到新空间,就可以自动做到类似翻译的效果

参考文献:Bilingual Word Embeddings for Phrase-Based Machine Translation, Will Zou, Richard Socher, Daniel Cer and Christopher Manning, EMNLP, 2013
在这个word embedding 不局限于文字,你可以对影像做embedding。举例:我们现在已经找好一组word vector,dog vector,horse vector,auto vector,cat vector在空间中是这个样子。接下来,你learn一个model,input一张image,output是跟word vector一样dimension的vector。你会希望说,狗的vector分布在狗的周围,马的vector散布的马的周围,车辆的vector散布在auto的周围,你可以把影像的vector project到它们对应的word vector附近。
假设有一张新的image进来(它是猫,但是你不知道它是猫),你通过同样的projection把它project这个space以后。神奇的是,你发现它就可能在猫的附近,machine就会知道这是个猫。我们一般做影像分类的时候,你的machine很难去处理新增加的,它没有看过的图片。如果你用这个方法的话,就算有一张image,在training的时候你没有看到过的class。比如说猫这个image,从来都没有看过,但是猫这个image project到cat附近的话,你就会说,这张image叫做cat。
如果你可以做到这件事的话,就好像是machine阅读了大量的文章以后,它知道说:每一个词汇它是什么意思。先通过阅读大量的文章,先了解词汇之间的关系,接下来再看image的时候,会根据它阅读的知识去match每一个image所该对应的位置。这样就算它没有看过的东西,它也有可能把它的名字叫出来。

除了Word Embedding,我们还可以对Document做Embedding
最简单的方法是把document变成bag-of-word,然后用Auto-encoder就可以得到该文档的语义嵌入(Semantic Embedding),但光这么做是不够的

词汇的顺序代表了很重要的含义,两句词汇相同但语序不同的话可能会有完全不同的含义,比如

想要解决这个问题,具体可以参考下面的几种处理方法(Unsupervised):
关于word2vec,可以参考博客:https://www.cnblogs.com/peghoty/p/3857839.html
机器不但要知道,还要告诉我们它为什么会知道。
Local Explanation——Why do you think this image is a cat?
Global Explanation——What do you think a “cat” looks like?
用机器来协助判断简历
用机器来协助判断犯人是否可以假释
金融相关的决策常常依法需要提供理由
模型诊断:到底机器学到了什么
We can improve ML model based on explanation.
当我们可以做可解释的机器学习模型时,我们就能做模型诊断,就可以知道机器到底学到了什么,是否和我们的预期相同。准确率不足以让我们精确调整模型,只有当我们知道why the answer is wrong, so i can fix it.
Goal of ML Explanation ≠ you completely know how the ML model work(Not necessary)
Goal of ML Explanation is —— Make people(your customers,your boss,yourself)comfortable.
Personalized explanation in the future
可解释机器学习的目标,不需要真正知道模型如何工作,只需要给出可信服的解释,让人满意就行。对此还可以针对不同人的接受能力给出不同层次的解释。
Some models are intrinsically interpretable.
Deep network is difficult to interpret.
Are there some models interpretable and powerful at the same time?
模型的可解释性和模型的能力之间有矛盾。
一些模型,比如线性模型,可解释性很好,但效果不佳。而深度网络,虽然能力一流,但缺乏可解释性。
我们的目标不是放弃复杂的模型,直接选择可解释性好的模型,而是让能力强的模型具有更好的解释性,去尝试解释复杂模型。
同时具有强大能力和可解释性的,是决策树。但决策树结构如果很复杂,那么可解释性也会很差。(森林)
假设我们的Object 有N个components,Image: pixel, segment, etc;Text: a word
We want to know the importance of each components for making the decision.
Removing or modifying the values of the components, observing the change of decision.
如果有Large decision change,那么就可以得到important component
比如找一个图片,把一个灰色的方块放在在图片中任意一个位置。当灰色方块位于某个位置导致机器判断改变,那么我们就把这个区域看为重要的component。注意,覆盖图片的方块的颜色、大小都是需要人工调整的参数,会影响结果,这其实是至关重要crucial的。甚至选择不同的参数可以得到不同的结果。
对于每一个输 将其某个维度加上一个小小的扰动,然后观察模型判断结果和原判断结果的差值,根据这个扰动造成的结果差值来了解机器对图片中哪些像素比较敏感。影响可以用来表示,计算方式就是偏微分:
得到的图称为:Saliency Map,亮度代表了偏微分的绝对值,也是pixel的重要性
Karen Simonyan, Andrea Vedaldi, Andrew Zisserman, “Deep Inside Convolutional Networks: Visualising Image Classification Models and Saliency Maps”, ICLR, 2014
Layer-wise Relevance Propagation
刚才我们用gradient的方法判断一个pixel或者一个segment是否重要,但是梯度有一个限制就是gradient saturation(梯度饱和)。我们如果通过鼻子的长度来判断一个生物是不是大象,鼻子越长是大象的信心分数越高,但是当鼻子长到一定程度信心分数就不太会变化了,信心分数就封顶了。鼻子长到一定程度,就可以确定这是一只大象,但是导数却是0,得出鼻子不重要这样的结论,明显是不对的。

攻击机器学习的解释是可能的。我们可以加一些神奇的扰动到图片上,人眼虽然辨识不出来,也不改变分类结果,但是模型聚焦的判定点却变了。

通过Saliency Map,看到机器更在意边缘,而非宝可梦的本体
All the images of Pokémon are PNG, while most images of Digimon are JPEG. PNG文件透明背景,读档后背景是黑的。Machine discriminate Pokémon and Digimon based on Background color.
This shows that explainable ML is very critical.
这块内容之前有讲过,就是找到一个图片,让某个隐藏层的输出最大,例如在手写数字辨识中,找出机器认为理想的数字如下

若不加限制,得到的结果经常会像是杂乱雪花,加一些额外的限制,使图像看起来更像数字(或其他正常图片)。我们不仅要maximize output的某个维度,还要加一个限制函数让尽可能像一个数字图片,这个函数输入是一张图片,输出是这张图片有多像是数字。
那这个限制函数要怎么定义呢,定义方式有很多种,这里就简单的定义为所有pixel的和的数值,这个值越小说明黑色RGB(0,0,0)越多,这个图片就越像是一个数字,由于这里数字是用白色的笔写的,所以就加一个负号,整体去maximize 与的和,形式化公式就变成了:
得到的结果如下图所示,比加限制函数之前要好很多了,从每个图片中多少能看出一点数字的形状了,尤其是6那一张。

With several regularization terms, and hyperparameter tuning …..
在更复杂的模型上,比如要在ImgNet这个大语料库训练出的模型上做上述的事情,在不加限制函数的情况下将会得到同样杂乱无章的结果。而且在这种复杂模型中要想得到比较好的Global Explanation结果,往往要加上更多、更复杂、更精妙的限制函数。
https://arxiv.org/abs/1506.06579
上面提到要对图片做一个限制,比较像一个图片,这个事情可以用Generator来做。
我们将方法转变为:找一个,将它输入到图片生成器中产生一个图片,再将这个图片输入原来的图片分类器,得到一个类别判断,我们同样要maximize . 其实可以考虑为我们把图片生成器和图片分类器连接在一起,fix住两者的参数,通过梯度下降的方法不断改变,最终找到一个合适的可以maximize .之后我们只要将这个丢入图片生成器就可以拿到图片了。形式化表述为:
调整输入低维向量z得到理想的y,把z通过generator就可以得到理想的image

这里和GAN里面的discriminator不一样,discriminator只会判断generator生成的图片好或者不好,这里是要生成某一个类型的图片。并且generator是固定的,我们调整的是低维向量z。
还有一种很神奇的方法用于解释模型,那就是用可解释的模型去模拟不可解释的模型,然后通过可解释的模型给出解释。
Some models are easier to Interpret. Using an interpretable model to mimic the behavior of an uninterpretable model.

具体思路也很简单,就是喂给目标模型一些样本并记录输出作为训练集,然后用这个训练集训练一个解释性良好的模型对目标模型进行解释。然而可解释性好的模型往往是比较简单的模型,可解释性差的模型往往是比较复杂的模型,用一个简单模型去模拟一个复杂模型无疑是困难的。上图就是一个示例。用线性模型去模拟一个神经网络效果肯定是很差的,但是我们可以做的是局部的模拟。

也就是说当我们给定一个输入的时候,我们要在这个输入附近找一些数据点,然后用线性模型进行拟合。那么当输入是图片的时候,什么样的数据算是这张图片附近的数据点呢?这需要不断调整参数。
Given a data point you want to explain
Sample at the nearby

Fit with linear (or interpretable) model

Interpret the model you learned

举例:
首先现有一张要解释的图片,我们想知道模型为什么把它认作树蛙
在这张图附近sample一些数据
我们通常会用一些toolkit把图片做一下切割,然后随机的丢掉一些图块,得到的新图片作为原图片附近区域中的数据点。
把上述这些图片输入原黑盒模型,得到黑盒的输出
用线性模型(或者其他可解释模型)fit上述数据
在上面的例子中我们在做图片辨识任务,此时我们可能需要在将图片丢到线性模型之前先做一个特征抽取。
解释你的线性模型
如上图所示,当线性模型种某个特征维度对应的weight:
下面用Decision Tree来代替上面的线性模型做解释工作。

Decision Tree足够复杂时,理论上完全可以模仿黑盒子的结果,但是这样Decision Tree会非常非常复杂,那么Decision Tree本身又变得没法解释了,因此我们不想Decision Tree太过复杂。这里我们用表示决策树的复杂度,定义方式可以自选,比如树的平均深度。
要考虑决策树的复杂度,因此要在损失函数中加一个正则项:

但是这个正则项没法做偏导,所以没有办法做GD。
解决方法:https://arxiv.org/pdf/1711.06178.pdf
train一个神奇的神经网络,我们给它一个神经网络的参数,它就可以输出一个数值,来表示输入的参数转成Decision Tree后Decision Tree的平均深度。
中心思想是用一个随机初始化的结构简单的Neural Network,找一些NN转成DT,算出平均深度,就有了训练data,训练后可以模拟出决策树的平均深度,然后用Neural Network替换上面的正则项,Neural Network是可以微分的,然后就可以Gradient Descent了。
We seek to deploy machine learning classifiers not only in the labs, but also in real world.
The classifiers that are robust to noises and work “most of the time” is not sufficient. We want the classifiers that are robust the inputs that are built to fool the classifier.
Especially useful for spam classification, malware detection, network intrusion detection, etc.
光是强还不够,还要应对人类的恶意攻击。
攻击是比较容易的,多数machine learning的model其实相当容易被各式各样的方法攻破,防御目前仍然是比较困难的。
给当前的machine输入一个图片,输出Tiger Cat的信息分数为0.64,你不会说它是一个很差的model,你会说它是一个做的还不错的model。
我们现在想要做的是:往图片上面加上一些杂讯,这些杂讯不是从gaussion distribution中随机生成的(随机生成的杂讯,没有办法真的对Network造成太大的伤害),这是种很特殊的讯号,把这些很特殊的讯号加到一张图片上以后,得到稍微有点不一样的图片。将这张稍微有点不一样的图片丢到Network中,Network会得到非常不一样的结果。
本来的图片叫做,而现在是在原来的上加上一个很特别的,得到一张新的图片()。然后将丢到Network中,原来看到时,Network会输出是一张Tiger Cat,但是这个Network看到时输出一个截然不同的答案(Attacked image,Else),那么这就是所谓攻击所要做的事情。

即找一张图片,使得loss(cross-entropy loss)越大越好,此时网络的参数训练完了,不能改变,而是只改变输入,使我们找到这样一张图片,能够让结果“越错越好”,离正确答案越远越好。
普通的训练模型,不变,希望找到一个θ,使cross-entropy越小越好
Non-targeted Attack,θ不变,希望找到一个,使得cross-entropy越大越好,cross-entropy越大Loss越小
Targeted Attack,希望找到一个,使得cross-entropy越大越好,同时与目标(错误)标签越近越好
输入不能改变太大, 和越接近越好

由任务的不同而不同,主要取决于对人来说什么样的文字、语音、图像信号是相似的。
L-infinity稍微更适合用于影像的攻击上面

损失函数的梯度为
Gradient Descent,但是加上限制,判断是否符合限制,如果不符合,要修正
修正方法:穷举附近的所有x,用距离最近的点来取代


使用一个猫,可以让它输出海星
两张图片的不同很小,要相减后乘以50倍才能看出
是否是因为网络很弱呢?随机加噪声,但是对结果的影响不大;加的噪声逐渐增大以后会有影响
高维空间中,随机方向与特定方向的y表现不同,因此一般的杂讯没有效果,特定的杂讯会有效果。
你可以想象 是在非常高维空间中的一个点,你把这个点随机的移动,你会发现多数情况下在这个点的附近很大一个范围内都是能正确辨识的空间,当你把这个点推到的很远的时候才会让机器识别成类似的事物,当你把它推的非常远时才会被辨识成不相关的事物。但是,有一些神奇维度,在这些神奇的维度上 的正确区域只有非常狭窄的一点点,我们只要将 推离原值一点点,就会让模型输出产生很大的变化。

这种现象不止存在于Deep Model中,一般的Model也会被攻击。
攻击方法的主要区别在于Different optimization methods和Different constraints
FGSM是一种简单的model attack方法,梯度下降的时候计算的梯度,如果是负的,则直接为-1,如果是正的,则直接为+1。所以的更新要么为,要么为,只更新一次就结束了。
这个算法的思想就是只攻击一次就好(减去或者加上)。多攻击几次确实会更好,所以FGSM有一个进阶方法Iterative fast gradient sign method(I-FGSM)

FGSM只在意gradient的方向,不在意它的大小。假设constrain用的是L-infinity,FGSM相当于设置了一个很大的learning rate,导致可以马上跳出范围,再拉回来。
In the previous attack, we fix network parameters 𝜃 to find optimal 𝑥′.
To attack, we need to know network parameters 𝜃
Are we safe if we do not release model?
No, because Black Box Attack is possible.
If you have the training data of the target network
Otherwise, obtaining input-output pairs from target network
如图中描述的是模型辨识正确的概率,也就是攻击失败的概率。上述五种神经网络的架构是不一样的,但是我们可以看到即使是不同架构的模型攻击成功的概率也是非常高的,而相同的架构的模型攻击成功率则明显是更高的。

核心精神是找一个通用的攻击向量,将其叠加到任意样本上都会让模型辨识出错。
https://arxiv.org/abs/1610.08401
这件事做成以后,你可以想象,只要在做辨识任务的摄像机前面贴一张噪声照片,就可以让所有结果都出错。另外,这个通用攻击甚至也可以做上述的黑盒攻击。

这个攻击的核心精神是:通过找一些噪声,让机器的行为发生改变,达到重编程实现其他功能的效果。改变原来network想要做的事情,例如从辨识动物变成数方块
当我们把图片中间贴上上图中那种方块图,机器就会帮我们数出途中方块的个数,如果有一个方块会输出tench,有两个方块就输出goldfish… 这件事还挺神奇的,因为我们并没有改变机器的任何参数,我们只是用了和前述相同的方法,找了一个噪声图片,然后把要数方块的图贴在噪声上,输入模型就会让模型帮我们数出方块的个数。具体方法细节参考引用文章。

我们想知道上述的攻击方法是否能应用在现实生活中,上述的所有方法中加入的噪声其实都非常的小,在数字世界中这些噪声会对模型的判别造成很大影响似乎是很合理的,但是在真实的世界中,机器是通过一个小相机看世界的,这样的小噪声通过相机以后可能就没有了。通过镜头是否会识别到那些微小的杂讯呢?实验把攻击的图像打印出来,然后用摄像头识别。证明这种攻击时可以在现实生活中做到的。
对人脸识别上进行攻击,可以把噪声变成实体眼镜,带着眼镜就可以实现攻击。
需要确保:多角度都是成功的;噪声不要有非常大的变化(比如只有1像素与其他不同),要以色块方式呈现,这样方便摄像头能看清;不用打印机打不出来的颜色。

在不同角度变成限速45的标志


Adversarial Attack cannot be defended by weight regularization, dropout and model ensemble.
Two types of defense
Passive defense: Finding the attached image without modifying the model
Proactive defense: Training a model that is robust to adversarial attack
加入filter,比如smoothing。


解释是,找攻击信号时,实际上只有某一种或者某几种攻击信号能够让攻击成功。虽然这种攻击信号能够让model失效,但是只有某几个方向上的攻击信号才能work。一旦加上一个filter,讯号改变了,攻击便失效。
先用正常的model做一个prediction,再用model之前加上squeeze模块的model做一个prediction,如果这两个prediction差距很大,说明这个image被攻击过。

还可以在原图基础上做一点小小的缩放,一些小padding,让攻击杂讯与原来不太一样,让攻击杂讯失效。

但问题是这样在model之前加“盾牌”的方法,有一个隐患是,如果,“盾牌”的机制被泄露出去,那么攻击仍然很有可能成功。(把filter想象成network的第一个layer,再去训练攻击杂讯即可)
精神:训练NN时,找出漏洞,补起来。
假设train T个iteration,在每一个iteration中,利用attack algorithm找出找出每一张图片的attack image,在把这些attack image标上正确的label,再作为training data,加入训练。这样的方法有点像data augmentation。
为什么需要进行T个iteration?因为加入新的训练数据后,NN的结构改变,会有新的漏洞出现。
This method would stop algorithm A, but is still vulnerable for algorithm B.
Defense今天仍然是个很困难,尚待解决的问题。

由于未来我们的模型有可能要运行在很多类似手机,手表,智能眼镜,无人机上,这些移动终端的算力和存储空间有限,因此要对模型进行压缩。当然也可以根据具体的硬件平台定制专门的模型架构,但这不是本课的重点。
Networks are typically over-parameterized (there is significant redundant weights or neurons)
Prune them!
先要训练一个很大的模型,然后评估出重要的权重或神经元,移除不重要的权重或神经元,After pruning, the accuracy will drop (hopefully not too much),要对处理后的模型进行微调,进行recovery把移除的损伤拿回来,若不满意就循环到第一步。注意:Don’t prune too much at once, or the network won’t recover.

怎么判断哪些参数是冗余或者不重要的呢?
How about simply train a smaller network?
It is widely known that smaller network is more difficult to learn successfully.
Larger network is easier to optimize? 更容易找到global optimum
Lottery Ticket Hypothesis
https://arxiv.org/abs/1803.03635
首先看最左边的网络,它表示大模型,我们随机初始化它权重参数(红色)。然后我们训练这个大模型得到训练后的模型以及权重参数(紫色)。最后我们对训练好的大模型做pruning得到小模型。作者把小模型拿出来后随机初始化参数(绿色,右上角),结果发现无法训练。然后他又把最开始的大模型的随机初始化的weight复制到小模型上(即把对应位置的权重参数复制过来,右下角)发现可以train出好的结果。
就像我们买彩票,买的彩票越多,中奖的机率才会越大。而最开始的大模型可以看成是由超级多的小模型组成的,也就是对大模型随机初始化参数会得到各种各样的初始化参数的小模型,有的小模型可能train不起来,但是有的就可以。大的Network比较容易train起来是因为,其中只要有小的Network可以train起来,大的Network就可以train起来。对大的Network做pruning,得到了可以train起来的小Network,因此它的初始参数是好的参数,用此参数去初始化,就train起来了。

Rethinking the Value of Network Pruning
这个文献提出了不同见解,其实直接train小的network也可以得到好的结果,无需初始化参数。Scratch-B比Scratch-E训练epoch多一些,可以看到比微调的结果要好。




我们可以使用一个student network来学习teacher network的输出分布,并计算两者之间的cross-entropy,使其最小化,从而可以使两者的输出分布相近。teacher提供了比label data更丰富的资料,比如teacher net不仅给出了输入图片和1很像的结果,还说明了1和7长得很像,1和9长得很像;所以,student跟着teacher net学习,是可以得到更多的information的。

可以让多个老师出谋划策来教学生,即通过Ensemble来进一步提升预测准确率。


在多类别分类任务中,我们用到的是softmax来计算最终的概率,但是这样有一个缺点,因为使用了指数函数,如果在使用softmax之前的预测值是,那么使用softmax之后三者对应的概率接近于,这样小模型没有学到另外两个分类的信息,和直接学习label没有区别。
引入了一个新的参数Temperature,通过T把y的差距变小了,导致各个分类都有机率,小模型学习的信息就丰富了。T需要自行调整。
Using less bits to represent a value
Weight clustering

Represent frequent clusters by less bits, represent rare clusters by more bits
Huffman Encoding
Binary Weights
Binary Connect
一种更加极致的思路来对模型进行压缩,Your weights are always +1 or -1
简单介绍一下Binary Connect的思路,如下图示,灰色节点表示一组binary weights,蓝色节点是一组real value weights
我们先计算出和蓝色节点最接近的灰色节点,并计算出其梯度方向(红色剪头)。
蓝色节点按照红色箭头方向更新,而不是按照自身的梯度方向更新。
最后在满足一定条件后(例如训练至最大epoch),蓝色节点会停在一个灰色节点附近,那么我们就使用该灰色节点的weights为Network的参数。


下图是低秩近似的简单示意图,左边是一个普通的全连接层,可以看到权重矩阵大小为M×N,而低秩近似的原理就是在两个全连接层之间再插入一层K。很反直观,插入一层后,参数还能变少?没错,的确变少了,我们可以看到新插入一层后的参数数量为K×(M+N),若让K不要太大,就可以减少Network的参数量。

但是低秩近似之所以叫低秩,是因为原来的矩阵的秩最大可能是,而新增一层后可以看到矩阵U和V的秩都是小于等于K的,我们知道,所以相乘之后的矩阵的秩一定还是小于等于K。
因此会限制Network的参数,限制原来Network所做到的事情。
看一下标准卷积所需要的参数量。如下图示,输入数据由两个6*6的feature map组成,之后用4个大小为3*3的卷积核做卷积,最后的输出特征图大小为4*4*4。每个卷积核参数数量为2*3*3=18,所以总共用到的参数数量为4*18=72。

首先是输入数据的每个通道只由一个二维的卷积核负责,即卷积核通道数固定为1,这样最后得到的输出特征图等于输入通道。

因为第一步得到的输出特征图是用不同卷积核计算得到的,所以不同通道之间是独立的,因此我们还需要对不同通道之间进行关联。为了实现关联,在第二步中使用了1*1大小的卷积核,通道数量等于输入数据的通道数量。另外1*1卷积核的数量等于预期输出特征图的数量,在这里等于4。最后我们可以得到和标准卷积一样的效果,而且参数数量更少,3 × 3 × 2 = 18、2 × 4 = 8,相比72个参数,合起来只用了26个参数。

与上文中插入一层linear hidden layer的思想相似,在其中插入feature map,使得参数减少
把filter当成神经元,可以发现Depthwise Separable Convolution是对普通Convolution filter的拆解。共用第一层filter的参数,第二层才用不同的参数。即不同filter间共用同样的参数。

下面我们算一下标准卷积和Depthwise Separable卷积参数量关系
假设输入特征图通道数为,输出特征图通道数为,卷积核大小为。
标准卷积参数量:
Depthwise Separable Convolution参数量:
两者相除,一般来说O很大,因此考虑后一项,k=3时,参数量变成原来的

这样的设计广泛运用在各种号称比较小的网络上面
SqueezeNet
MobileNet
ShuffleNet
Xception
Can network adjust the computation power it need? 该方法的主要思路是如果目前的资源充足(比如你的手机电量充足),那么算法就尽量做到最好,比如训练更久,或者训练更多模型等;反之,如果当前资源不够(如电量只剩10%),那么就先求有,再求好,先算出一个过得去的结果。
比如说我们提前训练多种网络,比如大网络,中等网络和小网络,那么我们就可以根据资源情况来选择不同的网络。但是这样的缺点是我们需要保存多个模型。
当资源有限时,我们可能只是基于前面几层提取到的特征做分类预测,但是一般而言这样得到的结果会打折扣,因为前面提取到的特征是比较细腻度的,可能只是一些纹理,而不是比较高层次抽象的特征。
左下角的图表就展示了不同中间层的结果比较,可以看到DenseNet和ResNet越靠近输入,预测结果越差。
右下角的图则展示了在不同中间层插入分类器对于模型训练的影响,可以看到插入的分类器越靠近输入层,模型的性能越差。
因为一般而言,前面的网络结构负责提取浅层的特征,但是当我们在前面就插入分类器后,那么分类器为了得到较好的预测结果会强迫前面的网络结构提取一些复杂的特征,进而扰乱了后面特征的提取。
具体的解决方法可以阅读Multi-Scale Dense Networks

Sentences are composed of characters/words

Images are composed of pixels

同样道理也可以用来生成一张照片,只要将每一个Pixel想成是一个Word,给模型一个BOS讯号,它就会开始生成颜色。

一般生成照片的时候如果单纯的按序生成可能会无法考量到照片之间的几何关系,但如果在生成Pixel的同时可以考量周围Pixel的话,那就可以有好的生成,可以利用3D Grid-LSTM
首先convolution filter在左下角计算,经过3D Grid-LSTM得到蓝色。filter右移一格,这时候会考虑蓝色,而3D Grid-LSTM的输入会往三个维度丢出,因此在计算第二个颜色的时候它会考虑到左边蓝色那排,得到红色。相同方式再一次得到黄色。filter往上一格移至左边起始点,同时会考量蓝色,才产生灰色。filter右移一格,这时候的filter计算含盖了灰、蓝、红三个资讯,得到黑色。

其他例子
Image
Video
Handwriting
Speech
We don’t want to simply generate some random sentences.
Generate sentences based on conditions.
单纯的利用RNN来产生句子那可能是不足的,因为它可以胡乱产生合乎文法的句子,因此我们希望模型可以根据某些条件来产生句子,也许给一张照片由机器来描述照片,或是像聊天机器人,给一个句子,机器回一个句子。
Represent the input condition as a vector, and consider the vector as the input of RNN generator.
将照片通过一个CNN产生一个Vector,在每一个时间点都将该Vector输入RNN,这样子每次产生的Word都会被该照片的Vector给影响,就不会是胡乱产生句子了。

相同做法也可以应用在机器翻译与聊天机器人上,例如机器翻译中把“机器学习”这个句子表示成一个vector(先通过另一个RNN,抽出最后一个时间点Hidden Layer的Output)丢到一个可以产生英语句子的RNN里即可。

前半部分称为Encoder,后半部分称为Decoder,两边可以结合一起训练参数,这种方式称为Sequence-to-Sequence Learning。资料量大时可以两边学习不同参数,资料量小时也可以共用参数(不容易过拟合)。
Need to consider longer context during chatting.
在聊天机器人中状况比较复杂,举例来说,机器人说了Hello之后,人类说了Hi,这时候机器人再说一次Hi就显的奇怪。因此机器必需要可以考虑比较长的资讯,它必需知道之前已经问过什么,或使用者说过什么。
我们可以再加入一个RNN来记忆对话,也就是双层的Encoder。首先,机器说的Hello跟人类回复的Hi都先变成一个code,接着第二层RNN将过去所有互动记录读一遍,变成一个code,再把这个结果做为后面Decoder的输入。
Dynamic Conditional Generation可以让机器考虑仅需要的information,让Decoder在每个时间点看到的information都是不一样的。
下图中的match是一个function,可以自己设计,“机”,“器”,“学”,“习”通过RNN得到各自的vector,是一个parameter。,上标1表示和算匹配度,下标0表示时间是0这个时间点,α的值表示匹配程度。
match function可以自己设计,无论是那种方式,如果match方法中有参数,要和模型一起训练jointly train

对每个输入都做match后,分别得到各自的,然后softmax得到,为加权的句子表示

可以是丢到RNN以后,hidden layer的output,也可以是其他。再去算一次match的分数

得到的就是下一个decoder的input,此时只关注“学”,“习”。

得到的再去match得到,直到生成句号。
input声音讯号,output是文字,甚至可以产生空格,但是seq2seq的方法效果目前还不如传统做法,完全不需要human knowledge是它的优点。

用一组vector描述image,比如用CNN filter的输出

产生划线词语时,attention的位置如图光亮处

当然也有不好的例子,但是从attention里面可以了解到它为什么会犯这些错误
从一段影像中也可以进行文字生成
Memory Network是在memory上面做attention,Memory Network最开始也是最常见的应用是在阅读理解上面,如下图所示:文章里面有很多句子组成,每个句子表示成一个vector,假设有N个句子,向量表示成,问题也用一个向量描述出来,接下来算问题与句子的匹配分数,做加权和,然后丢进DNN里面,就可以得到答案了。

Memory Network有一个更复杂的版本,这个版本是这样的,算match的部分跟抽取infromation的部分不见得是一样的,如果他们是不一样的,其实你可以得到更好的performance。把文档中的同一句子用两组向量表示;Query对x这一组vector算Attention,但是它是用h这一组向量来表示infromation,把这些Attention乘以h的加和得到提取的信息,放入DNN,得到答案。

通过Hopping可以反复进行运算,会把计算出的 extracted information 和 query 加在一起,重新计算 match score,然后又再算出一次 extracted information,就像反复思考一样。
如下图所示,我们用蓝色的vector计算attention,用橙色的vector做提取information。蓝色和蓝色,橙色和橙色的vector不一定是一样的。以下是两次加和后丢进去DNN得到答案。所以整件事情也可以看作两个layer的神经网络。

刚刚的 memory network 是在 memory 里面做 attention,并从 memory 中取出 information。而 Neural Turing Machine 还可以根据 match score 去修改 memory 中的内容。
初始 memory sequence 的第 i 个 vector
第 i 个 vector 初始的 attention weight
初始的 extracted information
可以是 DNN\LSTM\GRU... ,会 output 三个vector
用 一起计算出 match score 得到 ,然后 softmax,得到新的 attention ,计算 match score 的流程如下图

的作用分别是把之前的 memory 清空(erase),以及 写入新的 memory
的每个 dimension 的 output 都介于 0~1 之间
就是新的 memory,更新后再计算match score,更新 attention weight,计算,用于下一时刻模型输入

我们今天要做vedio的generation,我们给machine看一段如下的视频,如果你今天用的是Attention-based model的话,那么machine在每一个时间点会给vedio里面的每一帧(每一张image)一个attention,那我们用来代表attention,上标i代表是第i个component,下标t代表是时间点。那么下标是1的四个会得到,下标是2的四个会得到,下标是3的四个会得到,下标是4的四个会得到。
可能会有Bad Attention,如图所示,在得到第二个词的时候,attention(柱子最高的地方)主要在woman那儿,得到第四个词的时候,attention主要也在woman那儿,这样得到的不是一个好句子。
一个好的attention应该cover input所有的帧,而且每一帧的cover最好不要太多。最好的是:每一个input 组件有大概相同attention 权重。举一个最简单的例子,在本例中,希望在处理过程中所有attention的加和接近于一个值: ,这里的是类似于learning rate的一个参数。用这个正则化的目的是可以调整比较小的attention,使得整个的performance达到最好。
不要让attention过度关注于一个field,可以设置一个regularization term,使attention可以关注到其它的field。相当于加大其它component的权重 。

我们做的是 把condition和begin of sentence 丢进去,然后output一个distribution,颜色越深表示产生的机率越大,再把产生的output 作为下一个的input。
这里有一个注意的是,在training的时候,RNN 每个 step 的 input 都是正确答案 (reference),然而 testing 时,RNN 每个 step 的 input 是它上个 step 的 output (from model),可能输出与正确不同,这称为 Exposure Bias。
曝光误差简单来讲是因为文本生成在训练和推断时的不一致造成的。不一致体现在推断和训练时使用的输入不同,在训练时每一个词输入都来自真实样本,但是在推断时当前输入用的却是上一个词的输出。

如果把 training 的 process 改成:把上个 step 的 output 当成下个 step 的 input,听起来似乎很合理,不过实际上不太容易 train 起来。比如下图:在training的时候,与reference不同,假设你的gradient告诉你要使A上升,第二个输出时使B上升,如果让A的值上升,它的output就会改变,即第二个时间点的input就会不一样,那它之前学的让B上升就没有意义了,可能反而会得到奇怪的结果。

Scheduled Sampling通过修改我们的训练过程来解决上面的问题,一开始我们只用真实的句子序列进行训练,而随着训练过程的进行,我们开始慢慢加入模型的输出作为训练的输入这一过程。
我们纠结的点就是到底下一个时间点的input到底是从模型的output来呢,还是从reference来呢?这个Scheduled Sampling方法就说给他一个概率,概率决定以哪个作为input
一开始我们只用真实的句子序列(reference)进行训练,而随着训练过程的进行,我们开始慢慢加入模型的输出作为input这一过程。如果这样train的话,就可能得到更好的效果。


Beam Search是一个介于greedy search和暴力搜索之间的方法。第一个时间点都看,然后保留分数最高的k个,一直保留k个。
贪心搜索:直接选择每个输出的最大概率;暴力搜索:枚举当前所有出现的情况,从而得到需要的情况。
The green path has higher score.
Not possible to check all the paths

Keep several best path at each step
Beam Search方法是指在某个时间只pick几个分数最高的路径;选择一个beam size,即选择size个路径最佳。在搜索的时候,设置Beam size = 2,就是每一次保留分数最高的两条路径,走到最后的时候,哪一条分数最高,就输出哪一条。如下图所示:一开始,可以选择A和B两条路径,左边的第一个A点有两条路径,右边第一个B点有两条路径,此时一共有四条路径,选出分数最高的两条,再依次往下走 。

下一张图是如果使用beam search的时候,应该是怎么样的;
假设世界上只有三个词XYW和一个代表句尾的符号s,我们选择size=3,每一步都选最佳的三条路径。
输出分数最高的三个X,Y,W,再分别将三个丢进去,这样就得到三组不同的distribution(一共4*3条路径),选出分数最高的三条放入......

之前 Scheduled Sampling 要解决的 problem 为何不直接把 RNN 每个 step 的 output distribution 当作下一个 step 的 input 就好了呢? 有很多好处
老师直觉这个做法会变糟,原因如下:
如下图所示,对于左边,高兴和难过的机率几乎是一样的,所以我们现在选择高兴丢进去,后面接想笑的机率会很大;而对于右边,高兴和难过的机率几乎是一样的,想笑和想哭的机率几乎是一样的,那么就可能出现高兴想哭和难过想笑这样的输出,产生句子杂糅。

我们现在要生成的是整个句子,而不是单一的词语,所以我们在考量生成的结果好不好的时候,我们应该看一整个句子,而不是看单一的词汇。
举例来说,The dog is is fast,loss很小,但是效果并不好。用object level criterion可以根据整个句子的好坏进行评价。
但是使用这样的object level criterion是没办法做 gradient descent 的,因为看的是 RNN 的 hard output,即使生成 word 的机率有改变,只要最终 output 的 y 一样,那就不会变,也就是 gradient 仍然会是 0,无法更新。而cross entropy在调整参数的时候,是会变的,所以可以做GD

RL 的 reward,基本只有最后才会拿到,可以用这招来 maximize 我们的 object level criterion
前面的r都是0,只有最后一个参数通过调整得到一个reward。

Pointer Network最早是用来解决演算法(电脑算数学的学问)的问题。
举个例子:如下图所示,给出十个点,让你连接几个点能把所有的点都包含在区域内。拿一个NN出来,它的input就是10个坐标,我们期待它的输出是427653,就可以把十个点圈起来。那就要准备一大堆的训练数据;这个 Neural Network 的输入是所有点的坐标,输出是构成凸包的点的合集。

如何求解Pointer Network?
输入一排sequence,输出另一个sequence,理论上好像是可以用Seq2Seq解决的。那么这个 Network 可以用 seq2seq 的模式么?

答案是不行的,因为,我们并不知道输出的数据的多少。更具体地说,就是在 encoder 阶段,我们只知道这个凸包问题的输入,但是在 decoder 阶段,我们不知道我们一共可以输出多少个值。
举例来说,第一次我们的输入是 50 个点,我们的输出可以是 0-50 (0 表示 END);第二次我们的输入是 100 个点,我们的输出依然是 0-50, 这样的话,我们就没办法输出 51-100 的点了。
为了解决这个问题,我们可以引入 Attention 机制,让network可以动态决定输出有多大。
现在用Attention模型把这个sequence读取进来,第1-4个点在这边我们要加一个特殊的点,代表END的点。
接下来,我们就采用我们之前讲过的attention-based model,初始化一个key,即为,然后用这个key去做attention,用对每一input做attention,每一个input都产生有一个Attention Weight。
举例来说,在这边attention的weight是0.5,在这边attention的weight是0.3,在这边attention的weight是0.2,在这边attention的weight是0,在这边attention的weight是0.0。
这个attention weight就是我们输出的distribution,我们根据这个weight的分布取argmax,在这里,我取到,output 1,然后得到下一个key,即;同理,算权重,取argmax,得到下一个key,即,循环以上。
这样output set会跟随input变化

传统的seq2seq模型是无法解决输出序列的词汇表会随着输入序列长度的改变而改变的问题的,如寻找凸包等。因为对于这类问题,输出往往是输入集合的子集(输出严重依赖输入)。基于这种特点,考虑能不能找到一种结构类似编程语言中的指针,每个指针对应输入序列的一个元素,从而我们可以直接操作输入序列而不需要特意设定输出词汇表。


RNN是Recursive Network的subset

从RNN来看情绪分析的案例,将Word Sequence输入NN,经过相同的function-f最后经过function-g得到结果。
如果是Recursive Network的话,必需先决定这4个input word的structure,上图中,我们关联得到,关联得到
的维度必需要相同(因为用的是同一个f)。
输入和输出vector维度一致

中间的f是一个复杂的neural network,而不是两个单词vector的简单相加。
“good”: positive,“not”: neutral,“not good”: negative
“棒”: positive,“好棒”: positive,“好棒棒”: negative



function-f可以很简单,单纯的让a,b两个向量相加之后乘上权重W,但这么做可能无法满足我们上说明的需求期望,或者很难达到理想的效果。
当然也可以自己设计,比如:我们要让a,b两个向量是有相乘的关联,因此调整为下所示,两个向量堆叠之后转置乘上权重再乘上,它的计算逻辑就是将两个元素相乘之后再乘上相对应的权重索引元素值 做sum ,这么计算之后得到的是一个数值,而后面所得项目是一个2x1矩阵,无法相加,因此需要重复一次,要注意两个W颜色不同代表的是不同的权重值。

它的word vector有两个部分:一个是包含自身信息的vector,另一个是包含影响其他词关系的matrix。
经过如图所示计算,得到输出:两个绿色的点的matrix代表not good本身的意思,四个绿色的点是要影响别人的matrix,再把它们拉平拼接起来得到output。

Typical LSTM:h和m的输入对应相应的输出,但是h的输入输出差别很大,m的差别不大
Tree LSTM:就是把f换成LSTM

如果处理的是sequence,它背后的结构你是知道的,就可以使用Recursive Network,若结构越make sence(比如数学式),相比RNN效果越好
侦测两个句子是不是同一个意思,把两个句子分别得到embedding,然后再丢到f,把output输入到NN里面来预测

Seq2seq model with “Self-attention”
处理Seq2seq问题时一般会首先想到RNN,但是RNN的问题在于无论使用单向还是双向RNN都无法并行运算,输出一个值必须等待其依赖的其他部分计算完成。
为了解决并行计算的问题,可以尝试使用CNN来处理。如下图,使用CNN时其同一个卷积层的卷积核的运算是可以并行执行的,但是浅层的卷积核只能获取部分数据作为输入,只有深层的卷积层的卷积核才有可能会覆盖到比较广的范围的数据,因此CNN的局限性在于无法使用一层来输出考虑了所有数据的输出值。
self-attention可以取代原来RNN做的事情。输入是一个sequence,输出是另一个sequence。
它和双向RNN相同,每个输出也看过整个输入sequence,特别的地方是,输出是同时计算的。
You can try to replace any thing that has been done by RNN with self-attention.
首先input是到,是一个sequence。
每个input先通过一个embedding 变成到 ,然后丢进self-attention layer。
self-attention layer里面,每一个input分别乘上三个不同的transformation(matrix),产生三个不同的向量。这个三个不同的向量分别命名为q、k、v。
现在每个时刻,每个都有q、k、v三个不同的向量。
接下来要做的事情是拿每一个q对每个k做attention。attention是吃两个向量,output一个分数,告诉你这两个向量有多匹配,至于怎么吃这两个向量,则有各种各样的方法,这里我们采用Scaled Dot-Product Attention,和做点积,然后除以。
d是q跟k的维度,因为q要跟k做点积,所以维度是一样的。因为dim越大,点积结果越大,因此除以一个来平衡。
现在就得到了sequence的第一个向量 。在产生的时候,用了整个sequence的信息,看到了到的信息。如果你不想考虑整个句子的信息,只想考虑局部信息,只要让的值为0,意味着不会考虑的信息。如果想考虑某个的信息,只要让对应的有值即可。所以对self-attention来说,只要它想看,就能用attention看到,只要自己学习就行。
在同一时间,就可以用同样的方式,把也算出来。





反正就是一堆矩阵乘法,用 GPU 可以加速

(2 heads as example)
在2个head的情况下,你会进一步把分裂,变成,做法是可以乘上两个矩阵。
也一样,产生和。
但是现在只会对(同样是第一个向量)做attention,然后计算出

只会对做attention,然后得到。

然后把接在一起,如果你还想对维度做调整,那么再乘上一个矩阵做降维就可以了。

有可能不同的head关注的点不一样,比如有的head想看的是local(短期)的信息,有的head想看的是global(长期)的信息。有了Multi-head之后,每个head可以各司其职,自己做自己想做的事情。
当然head的数目是可以自己调的,比如8个head,10个head等等都可以。
No position information in self-attention.
但是这个显然不是我们想要的,我们希望把input sequence的顺序考虑进self-attention layer里去。
在原始的paper中说,在把变成后,还要加上一个(要跟的维度相同),是人工设定的,不是学出来的,代表了位置的信息,所以每个位置都有一个不同的。比如第一个位置为,第二个位置为......。
把加到后,接下来的步骤就跟之前的一样。
通常这里会想,为什么跟是相加,而不是拼接,相加不是把位置信息混到里去了吗
我们可以想象,给再添加一个one-hot向量(代表了位置信息),是一个很长的向量,位置i为1,其他为0。
拼接后乘上一个矩阵W,你可以想像为等于把W拆成两个矩阵,之后跟相乘+跟相乘。而跟相乘部分就是跟相乘部分是 ,那么就是,所以相加也是说得通的。
是可以学习的,但是有人做过实验,学出来的效果并不如手动设定好。


Encode:所有word两两之间做attention,有三个attention layer
Decode:不只 attend input 也会attend 之前已经输出的部分
More specifically, to compute the next representation for a given word - “bank” for example - the Transformer compares it to every other word in the sentence. The result of these comparisons is an attention score for every other word in the sentence. These attention scores determine how much each of the other words should contribute to the next representation of “bank”. In the example, the disambiguating “river” could receive a high attention score when computing a new representation for “bank”. The attention scores are then used as weights for a weighted average of all words’ representations which is fed into a fully-connected network to generate a new representation for “bank”, reflecting that the sentence is talking about a river bank.
The animation above illustrates how we apply the Transformer to machine translation. Neural networks for machine translation typically contain an encoder reading the input sentence and generating a representation of it. A decoder then generates the output sentence word by word while consulting the representation generated by the encoder. The Transformer starts by generating initial representations, or embeddings, for each word. These are represented by the unfilled circles. Then, using self-attention, it aggregates information from all of the other words, generating a new representation per word informed by the entire context, represented by the filled balls. This step is then repeated multiple times in parallel for all words, successively generating new representations.
The decoder operates similarly, but generates one word at a time, from left to right. It attends not only to the other previously generated words, but also to the final representations generated by the encoder.
Using Chinese to English translation as example
左半部是encoder,右半部是decoder。encoder的输入是机器学习(一个中文的character),decoder先给一个begin token ,然后输出machine,在下一个时间点把machine作为输入,输出learning,这个翻译的过程就结束了。

接下来看里面的每个layer在干什么。

Encoder:
input通过一个input embedding layer变成一个向量,然后加上位置encoding向量
然后进入灰色的block,这个block会重复多次
第一层是Multi-Head Attention,input一个sequence,输出另一个sequence
第二层是Add&Norm
第三层是Feed Forward,会把sequence 的每个b'向量进行处理
第四层是另一个Add&Norm
最终输出的是输入信号的向量表示
Decoder:
decoder的input是前一个时间点产生的output,通过output embedding,再加上位置encoding变成一个向量,然后进去灰色的block,灰色block同样会重复多次
不再循环后,进行Linear,最后再进行softmax
Transformer paper最后附上了一些attention的可视化,每两个word之间都会有一个attention。attention权重越大,线条颜色越深。
现在input一个句子,在做attention的时候,你会发现it attend到animal;但是把tired换成wide,it会attend到street。

对于Multi-head attention,每一组都做不同的事情,这里会发现,确实是这样。如下图所示,上面的部分可以看出这个head主要关注比较长序列(global)的信息,而下面的head比较关注距自己相近的序列(local)的信息,说明使用多个head时不同的head通过学习会关注不同的信息。

使用Transformer可以做多文档摘要,通过训练一个Summarizer来输入一个文档的集合然后输出这些文档的摘要。https://arxiv.org/abs/1801.10198
Transformer很好地解决了输入序列长度较大的情况,而向RNN中输入长序列结果通常不会好。
将Transfromer在深度上随时间循环使用,即重复使用相同的网络结构。
https://ai.googleblog.com/2018/08/moving-beyond-translation-with.html
将Transfromer用在影像上,用每一个pixel去attention其他pixel,这样可以考虑到比较global的信息。
https://arxiv.org/abs/1805.08318
无监督学习(Unsupervised Learning)可以分为两种:
化繁为简
无中生有(Generation)
对于无监督学习(Unsupervised Learning)来说,我们通常只会拥有中的或,其中:

聚类,顾名思义,就是把相近的样本划分为同一类,比如对下面这些没有标签的image进行分类,手动打上cluster 1、cluster 2、cluster 3的标签,这个分类过程就是化繁为简的过程
一个很critical的问题:我们到底要分几个cluster?
最常用的方法是K-means:
我们有一大堆的unlabeled data ,我们要把它划分为K个cluster
对每个cluster都要找一个center ,initial的时候可以从training data里随机挑K个object 出来作为K个center 的初始值
Repeat
注:如果不是从原先的data set里取center的初始值,可能会导致部分cluster没有样本点
HAC,全称Hierarchical Agglomerative Clustering,层次聚类
假设现在我们有5个样本点,想要做clustering:
build a tree:
整个过程类似建立Huffman Tree,只不过Huffman是依据词频,而HAC是依据相似度建树
pick a threshold:
选取阈值,形象来说就是在构造好的tree上横着切一刀,相连的叶结点属于同一个cluster
下图中,不同颜色的横线和叶结点上不同颜色的方框对应着切法与cluster的分法

HAC和K-means最大的区别在于如何决定cluster的数量,在K-means里,K的值是要你直接决定的;而在HAC里,你并不需要直接决定分多少cluster,而是去决定这一刀切在树的哪里
clustering的缺点是以偏概全,它强迫每个object都要属于某个cluster
但实际上某个object可能拥有多种属性,或者多个cluster的特征,如果把它强制归为某个cluster,就会失去很多信息;我们应该用一个vector来描述该object,这个vector的每一维都代表object的某种属性,这种做法就叫做Distributed Representation,或者说,Dimension Reduction
如果原先的object是high dimension的,比如image,那现在用它的属性来描述自身,就可以使之从高维空间转变为低维空间,这就是所谓的降维(Dimension Reduction)
接下来我们从另一个角度来看为什么Dimension Reduction可能是有用的
假设data为下图左侧中的3D螺旋式分布,你会发现用3D的空间来描述这些data其实是很浪费的,因为我们完全可以把这个卷摊平,此时只需要用2D的空间就可以描述这个3D的信息

如果以MNIST(手写数字集)为例,每一张image都是28*28 dimension,但我们反过来想,大多数28*28 dimension的vector转成image,看起来都不会像是一个数字,所以描述数字所需要的dimension可能远比28*28要来得少。
举一个极端的例子,对于只是存在角度差异的image,我们完全可以用某张image旋转的角度来描述,也就是说,我们只需要用这1个dimension就可以描述原先28*28 dims的图像
在Dimension Reduction里,我们要找一个function,这个function的input是原始的x,output是经过降维之后的z
最简单的方法是Feature Selection,即直接从原有的dimension里拿掉一些直观上就对结果没有影响的dimension,就做到了降维,比如下图中从两个维度中直接拿掉;但这个方法不总是有用,因为很多情况下任何一个dimension其实都不能被拿掉。

另一个常见的方法叫做PCA(Principe Component Analysis)
PCA认为降维就是一个很简单的linear function,它的input x和output z之间是linear transform,即,PCA要做的,就是根据一大堆的x把W给找出来(未知)
为了简化问题,这里我们假设z是1维的vector,也就是把x投影到一维空间
注:为行向量,为列向量,下文中表示的是矢量内积,而表示的是矩阵相乘
,为Scalar,其中表示的第一个row vector,假设的长度为1,即,那跟做内积得到的意味着:是高维空间中的一个点,是高维空间中的一个vector,此时就是在上的投影,投影的值就是和的inner product
那我们到底要找什么样的呢?
假设我们现在已有的宝可梦样本点分布如下,横坐标代表宝可梦的攻击力,纵坐标代表防御力,我们的任务是把这个二维分布投影到一维空间上
我们希望选这样一个,它使得经过投影之后得到的分布越大越好,也就是说,经过这个投影后,不同样本点之间的区别,应该仍然是可以被看得出来的,即:
下图给出了所有样本点在两个不同的方向上投影之后的variance比较情况

当然我们不可能只投影到一维空间,我们还可以投影到更高维的空间
对来说:
串起来就得到列向量,而分别是的第1,2,...个row,需要注意的是,这里的必须相互正交,此时是正交矩阵(orthogonal matrix),如果不加以约束,则找到的实际上是相同的值
两个矩阵相乘的意义是将右边矩阵中的每一列列向量变换到左边矩阵中每一行行向量为基所表示的空间中去。
如果我们有M个N维向量,想将其变换为由R个N维向量表示的新空间中,那么首先将R个基按行组成矩阵A,然后将向量按列组成矩阵B,那么两矩阵的乘积AB就是变换结果,其中AB的第m列为A中第m列变换后的结果。我们可以将一N维数据变换到更低维度的空间中去,变换后的维度取决于基的数量。因此这种矩阵相乘的表示也可以表示降维变换。

求解PCA,实际上已经有现成的函数可以调用,此外你也可以把PCA描述成neural network,然后用gradient descent的方法来求解,这里主要介绍用拉格朗日乘数法(Lagrange multiplier)求解PCA的数学推导过程


注:根据PPT,为列向量,和为多个列向量
首先计算出:
然后计算maximize的对象:
其中
当然这里想要求的最大值,还要加上的约束条件,否则可以取无穷大
令,它是:
目标:maximize ,条件:
使用拉格朗日乘数法,利用目标和约束条件构造函数:
对这个vector里的每一个element做偏微分:
整理上述推导式,可以得到:
其中,是S的特征向量(eigenvector)
注意到满足的特征向量有很多,我们要找的是可以maximize 的那一个,于是利用上一个式子:
在推导时,相较于,多了一个限制条件:必须与正交(orthogonal)
目标:maximize ,条件:
同样是用拉格朗日乘数法求解,先写一个关于的function,包含要maximize的对象,以及两个约束条件
对的每个element做偏微分:
整理后得到:
上式两侧同乘,得到:
其中,
而由于是vector×matrix×vector=scalar,因此在外面套一个transpose不会改变其值,因此该部分可以转化为:
注:S是symmetric的,因此
我们已经知道满足,代入上式:
因此有,,,又根据
可以推得
此时就转变成了,即
由于是symmetric的,因此在不与冲突的情况下,这里选取第二大的特征值时,可以使最大
结论:也是这个matrix中的特征向量,对应第二大的特征值
神奇之处在于,即z的covariance是一个diagonal matrix
如果你把原来的input data通过PCA之后再给其他model使用,其它的model就可以假设现在的input data它的dimension之间没有decorrelation。所以它就可以用简单的model处理你的input data,参数量大大降低,相同的data量可以得到更好的训练结果,从而可以避免overfitting的发生

假设我们现在考虑的是手写数字识别,这些数字是由一些类似于笔画的basic component组成的,本质上就是一个vector,记做,以MNIST为例,不同的笔画都是一个28×28维的vector,把某几个vector加起来,就组成了一个28×28维的digit
写成表达式就是:
其中代表某张digit image中的pixel,它等于k个component的加权和加上所有image的平均值
比如7就是,我们可以用来表示一张digit image,如果component的数目k远比pixel的数目要小,那这个描述就是比较有效的

实际上目前我们并不知道~具体的值,因此我们要找这样k个vector,使得与越接近越好:
而用未知component来描述的这部分内容,叫做Reconstruction error,即
接下来我们就要去找k个vector 去minimize这个error:
回顾PCA,
实际上我们通过PCA最终解得的就是使reconstruction error最小化的,简单证明如下:


下面的式子简单演示了将一个样本点划分为k个组件的过程,其中是每个组件的比例;把划分为k个组件即从n维投影到k维空间,也是投影结果
注:和均为n维列向量
现在我们已经知道,用PCA找出来的就是k个component
而,我们要使与之间的差距越小越好,我们已经根据SVD找到了的值,而对每个不同的样本点,都会有一组不同的值
在PCA中我们已经证得,这k个vector是标准正交化的(orthonormal),因此:
这个时候我们就可以使用神经网络来表示整个过程,假设是3维向量,要投影到k=2维的component上:
对与做inner product的过程中,在3维空间上的坐标就相当于是neuron的input,而,,则是neuron的weight,表示在这个维度上投影的参数,而则是这个neuron的output,表示在这个维度上投影的坐标值;对也同理

得到之后,再让它乘上,得到的一部分


此时,PCA就被表示成了只含一层hidden layer的神经网络,且这个hidden layer是线性的激活函数,训练目标是让这个NN的input 与output 越接近越好,这件事就叫做Autoencoder
PCA looks like a neural network with one hidden layer (linear activation function)
注意,通过PCA求解出的与直接对上述的神经网络做梯度下降所解得的是会不一样的,因为PCA解出的是相互垂直的(orgonormal),而用NN的方式得到的解无法保证相互垂直,NN无法做到Reconstruction error比PCA小,因此:
PCA有很明显的弱点:
它是unsupervised的,如果我们要将下图绿色的点投影到一维空间上,PCA给出的从左上到右下的划分很有可能使原本属于蓝色和橙色的两个class的点被merge在一起;
LDA是考虑了labeled data之后进行降维的一种方式,属于supervised
它是linear的,对于下图中的彩色曲面,我们期望把它平铺拉直进行降维,但这是一个non-linear的投影转换,PCA无法做到这件事情,PCA只能做到把这个曲面打扁压在平面上,类似下图,而无法把它拉开
对类似曲面空间的降维投影,需要用到non-linear transformation(non-linear dimension reduction)

用PCA来分析宝可梦的数据
假设总共有800只宝可梦,每只都是一个六维度的样本点,即vector={HP, Atk, Def, Sp Atk, Sp Def, Speed},接下来的问题是,我们要投影到多少维的空间上?要多少个component就好像是neural network要几个layer,每个layer要有几个neural一样,所以这是你要自己决定的。
如果做可视化分析的话,投影到二维或三维平面可以方便人眼观察。
一个常见的方法是这样的:我们去计算每一个principle components的(每一个principle component 就是一个eigenvector,一个eigenvector对应到一个eigenvalue )。这个eigenvalue代表principle component去做dimension reduction的时候,在principle component的那个dimension上,它的variance有多大(variance就是)。
今天这个宝可梦的data总共有6维,所以covariance matrix是有6维。你可以找出6个eigenvector,找出6个eigenvalue。现在我们来计算一下每个eigenvalue的ratio(每个eigenvalue除以6个eigenvalue的总和),得到的结果如图。

可以从这个结果看出来说:第五个和第六个principle component的作用是比较小的,你用这两个dimension来做projection的时候project出来的variance是很小的,代表说:现在宝可梦的特性在第五个和第六个principle component上是没有太多的information。所以我们今天要分析宝可梦data的话,感觉只需要前面四个principle component就好了。
我们实际来分析一下,做PCA以后得到四个principle component就是这个样子,每一个principle component就是一个vector,每一个宝可梦是用6维的vector来描述。
如果你要产生一只宝可梦的时候,每一个宝可梦都是由这四个vector做linear combination,
新的维度本质上就是旧的维度的加权矢量和,下图给出了前4个维度的加权情况,从PC1到PC4这4个principle component都是6维度加权的vector,它们都可以被认为是某种组件,大多数的宝可梦都可以由这4种组件拼接而成,也就是用这4个6维的vector做linear combination的结果
我们来看每一个principle component做的事情是什么:
对第一个vector PC1来说,每个值都是正的,在选第一个principle component的时候,你给它的weight比较大,那这个宝可梦的六维都是强的,所以这第一个principle component就代表了这一只宝可梦的强度。
对第二个vector PC2来说,防御力Def很大而速度Speed很小,你给第二个principle component一个weight的时候,你会增加那只宝可梦的防御力但是会减低它的速度。
如果将宝可梦仅仅投影到PC1和PC2这两个维度上,则降维后的二维可视化图像如下图所示:
从该图中也可以得到一些信息:

对第三个principle component来说,sp Def很大而HP和Atk很小,这个组件是用生命力和攻击力来换取特殊防御力。
对第四个vector PC4来说,HP很大而Atk和Def很小,这个组件是用攻击力和防御力来换取生命力
同样将宝可梦只投影到PC3和PC4这两个维度上,则降维后得到的可视化图像如下图所示:
该图同样可以告诉我们一些信息:

我们拿它来做手写数字辨识的话,我们可以把每一张数字都拆成component乘以weight,加上另外一个component乘以weight,每一个component是一张image(28* 28的vector)。
我们现在来画前PCA得到的前30个component的话,你得到的结果是这样子的(如图所示),你用这些component做linear combination,你就得到所有的digit(0-9),所以这些component就叫做Eigen digits(这些component其实都是covariance matrix的eigenvector)
注:PCA就是求的前30个最大的特征值对应的特征向量

同理,通过PCA找出人脸的前30个principle component,得到的结果是这样子的。这些叫做Eigen-face。你把这些脸做linear combination以后就可以得到所有的脸。但是这边跟我们预期的有些是不一样的,因为现在我们找出来的不是component,我们找出来的每一个图都几乎是完整的脸。

在对MNIST和Face的PCA结果展示的时候,你可能会注意到我们找到的组件好像并不算是组件,比如MNIST找到的几乎是完整的数字雏形,而Face找到的也几乎是完整的人脸雏形,但我们预期的组件不应该是类似于横折撇捺,眼睛鼻子眉毛这些吗?
如果你仔细思考了PCA的特性,就会发现得到这个结果是可能的
注意到linear combination的weight 可以是正的也可以是负的,因此我们可以通过把组件进行相加或相减来获得目标图像,这会导致你找出来的component不是基础的组件,但是通过这些组件的加加减减肯定可以获得基础的组件元素
如果你要一开始就得到类似笔画这样的基础组件,就要使用NMF(non-negative matrix factorization),非负矩阵分解的方法
PCA可以看成对原始矩阵做SVD进行矩阵分解,但并不保证分解后矩阵的正负,实际上当进行图像处理时,如果部分组件的matrix包含一些负值的话,如何处理负的像素值也会成为一个问题(可以做归一化处理,但比较麻烦)
而NMF的基本精神是,强迫使所有组件和它的加权值都必须是正的,也就是说所有图像都必须由组件叠加得到:
Forcing , ...... be non-negative
Forcing , ...... be non-negative
注:关于NMF的具体算法内容可参考paper(公众号回复“NMF”获取pdf):
Daniel D. Lee and H. Sebastian Seung. "Algorithms for non-negative matrix factorization."Advances in neural information processing systems. 2001.
在MNIST数据集上,通过NMF找到的前30个组件如下图所示,可以发现这些组件都是由基础的笔画构成:

在Face数据集上,通过NMF找到的前30个组价如下图所示,相比于PCA这里更像是脸的一部分

降维的方法有很多,这里再列举一些与PCA有关的方法:
Multidimensional Scaling (MDS) [Alpaydin, Chapter 6.7]
MDS不需要把每个data都表示成feature vector,只需要知道特征向量之间的distance,就可以做降维
一般教科书举的例子会说:我现在一堆城市,你不知道如何把城市描述成vector,但你知道城市跟城市之间的距离(每一笔data之间的距离),那你就可以画在二维的平面上。
其实MDS跟PCA是有一些关系的,如果你用某些特定的distance来衡量两个data point之间的距离的话,你做MDS就等于做PCA。
其实PCA有个特性是:它保留了原来在高维空间中的距离(在高维空间的距离是远的,那么在低维空间中的距离也是远的,在高维空间的距离是近的,那么在低维空间中的距离也是近的)
Probabilistic PCA [Bishop, Chapter 12.2]
PCA概率版本
Kernel PCA [Bishop, Chapter 12.3]
PCA非线性版本
Canonical Correlation Analysis (CCA) [Alpaydin, Chapter 6.9]
CCA常用于两种不同的data source的情况,假如说你要做语音辨识,两个source(一个是声音讯号,另一个是嘴巴的image,可以看到这个人的唇形)把这两种不同的source都做dimension reduction,那这个就是CCA。
Independent Component Analysis (ICA)
ICA常用于source separation,PCA找的是正交的组件,而ICA则只需要找“独立”的组件即可
Linear Discriminant Analysis (LDA) [Alpaydin, Chapter 6.8]
LDA是supervised的方式
通过一个详细的例子分析矩阵分解思想及其在推荐系统上的应用
接下来介绍矩阵分解的思想:有时候存在两种object,它们之间会受到某种共同潜在因素(latent factor)的操控,如果我们找出这些潜在因素,就可以对用户的行为进行预测,这也是推荐系统常用的方法之一
假设我们现在去调查每个人购买的公仔数目,ABCDE代表5个人,每个人或者每个公仔实际上都是有着傲娇的属性或天然呆的属性
我们可以用vector去描述人和公仔的属性,如果某个人的属性和某个公仔的属性是match的,即他们背后的vector很像(内积值很大),这个人就会偏向于拥有更多这种类型的公仔

但是,我们没有办法直接观察某个人背后这些潜在的属性,也不会有人在意一个肥宅心里想的是什么;我们同样也没有办法直接得到动漫人物背后的属性;
我们目前有的,只是动漫人物和人之间的关系,即每个人已购买的公仔数目,我们要通过这个关系去推测出动漫人物与人背后的潜在因素(latent factor)
我们可以把每个人的属性用vector 、、、、来表示,而动漫人物的属性则用vector 、、、来表示,购买的公仔数目可以被看成是matrix ,对来说,行数为人数,列数为动漫角色的数目
做一个假设:matrix 里的每个element,都是属于人的vector和属于动漫角色的vector的内积
比如,,表示和的属性比较贴近
接下来就用下图所示的矩阵相乘的方式来表示这样的关系,其中为latent factor的数量,这是未知的,需要你自己去调整选择
我们要找一组~和~,使得右侧两个矩阵相乘的结果与左侧的matrix 越接近越好,可以使用SVD的方法求解

但有时候,部分的information可能是会missing的,这时候就难以用SVD精确描述,但我们可以使用梯度下降的方法求解,loss function如下:
其中值的是人背后的latent factor,指的是动漫角色背后的latent factor,我们要让这两个vector的内积与实际购买该公仔的数量越接近越好,这个方法的关键之处在于,计算上式时,可以跳过missing的数据,最终通过gradient descent求得和的值

假设latent factor的数目等于2,则人的属性和动漫角色的属性都是2维的vector,这里实际进行计算后,把属性中较大值标注出来,可以发现:
这也是推荐系统的常用方法

实际上除了人和动漫角色的属性之外,可能还存在其他因素操控购买数量这一数值,因此我们可以将式子更精确地改写为:
其中这个Scalar表示A这个人本身有多喜欢买公仔,这个Scalar则表示这个动漫角色本身有多让人想要购买,这些内容是跟属性vector无关的,此时Minimizing的loss function被改写为:
当然你也可以加上一些regularization去对结果做约束
Paper Ref: Matrix Factorization Techniques For Recommender Systems
如果把matrix factorization的方法用在topic analysis上,就叫做LSA(Latent semantic analysis),潜在语义分析

把刚才的动漫人物换成文章,把刚才的人换成词汇,table里面的值就是term frequency(词频),把这个term frequency乘上一个weight代表说这个term本身有多重要。
怎样evaluation一个term重不重要呢?常用的方式是:inverse document frequency(计算某一个词汇在整个paper有多少比率的document涵盖这个词汇,假如说,某一个词汇,每个document都有,那它的inverse document frequency就很小,代表着这个词汇的重要性是低的,假设某个词汇只有某一篇document有,那它的inverse document frequency就很大,代表这个词汇的重要性是高的。在各种文章中出现次数越多的词汇越不重要,出现次数越少则越重要。)
在这个task里面,如果你今天把这个matrix做分解的话,你就会找到每一个document背后那个latent factor,那这边的latent factor是什么呢?可能指的是topic(主题),这个topic有多少是跟财经有关的,有多少是跟政治有关的。document1跟document2有比较多的“投资,股票”这样的词汇,那document1跟document2的latent factor有比较高的可能性是比较偏向“财经”的
topic analysis的方法多如牛毛,基本的精神是差不多的(有很多各种各样的变化)。常见的是Probability latent semantic analysis (PLSA)和latent Dirichlet allocation (LDA)。注意这跟之前在machine learning讲的LDA是完全不一样的东西。
介绍非线性降维的一些算法,包括局部线性嵌入LLE、拉普拉斯特征映射和t分布随机邻居嵌入t-SNE,其中t-SNE特别适用于可视化的应用场景
PCA和Word Embedding介绍了线性降维的思想,而Neighbor Embedding要介绍的是非线性的降维
我们知道data point可能是在高维空间里面的一个manifold,也就是说:data point的分布其实是在低维的一个空间里,只是被扭曲地塞到高维空间里面。
讲到manifold ,常常举的例子是地球,地球的表面就是一个manifold(一个二维的平面,被塞到一个三维的空间里面)。
在manifold里面只有很近距离的点,欧氏距离Euclidean distance才会成立,如果距离很远的时候,欧式几何不一定成立。
所以manifold learning要做的事情是把S型的这块东西展开,把塞到高维空间的低维空间摊平。摊平的好处就是:把这个塞到高维空间里的manifold摊平以后,那我们就可以在这个manifold上面用Euclidean distance来算点和点之间的距离,描述样本点之间的相似程度,这会对接下来你要做supervised learning都是会有帮助的。

局部线性嵌入,locally linear embedding,简称LLE
在原来的空间里面,有某一个点叫做,我们先选出的neighbor叫做。接下来我们找跟之间的关系,它们之间的关系我们写作。
我们假设说:每一个都是可以用它的neighbor做linear combination以后组合而成,这个是拿组成的时候,linear combination的weight。因此找点与点的关系这个问题就转换成,找一组使得所有样本点与周围点线性组合的差距能够最小的参数。那找这一组要如何做呢,我们现在找一组,减掉summation over乘以的L2-Norm越接近越好,然后summation over所以的data point i。

接下来就要做Dimension Reduction,把和降维到和,并且保持降维前后两个点之间的关系是不变的

LLE的具体做法如下:
在原先的高维空间中找到和之间的关系以后就把它固定住
使和降维到新的低维空间上的和
和需要minimize下面的式子:
即在原本的空间里,可以由周围点通过参数进行线性组合得到,则要求在降维后的空间里,也可以用同样的线性组合得到
实际上,LLE并没有给出明确的降维函数,它没有明确地告诉我们怎么从降维到,只是给出了降维前后的约束条件。它并没有一个明确的function告诉你说我们如何来做dimension reduction,不像我们在做auto encoding的时候,你learn出一个encoding的network,你input一个新的data point,然后你就得到dimension结果。在LLE里面,你并没有找一个明确的function告诉我们,怎么样从一个x变到z,z完全就是另外凭空找出来的。
在实际应用LLE的时候,LLE要好好的调neighbor,neighbor的数目要刚刚好,对来说,需要选择合适的邻居点数目K才会得到好的结果
下图给出了原始paper中的实验结果,K太小或太大得到的结果都不太好。
为什么k太大,得出的结果也不好呢?因为我们之前的假设是Euclidean distance只是在很近的距离里面可以这样想,当k很大的时候,你会考虑很远的点,所以你不应该把它考虑进来,你的k要选一个适当的值。注意到在原先的空间里,只有距离很近的点之间的关系需要被保持住,如果K选的很大,就会选中一些由于空间扭曲才导致距离接近的点,而这些点的关系我们并不希望在降维后还能被保留。

另一种方法叫拉普拉斯特征映射,Laplacian Eigenmaps
之前在semi-supervised learning有提到smoothness assumption,即我们仅知道两点之间的欧氏距离是不够的,还需要观察两个点在high density区域下的距离,如果两个点之间有high density connection,那它们才是真正的很接近。
我们依据某些规则把样本点建立graph,把比较近的点连起来,变成一个graph,那么smoothness的距离就可以被graph上面的connection来approximate

简单回顾一下在semi-supervised里的说法:如果两个点和在高密度区域上是相近的,那它们的label 和很有可能是一样的
其中表示labeled data项,表示unlabeled data项,它就像是一个regularization term,用于判断我们当前得到的label是否是smooth的
其中如果点与是相连的,则等于相似度,否则为0,的表达式希望在与很接近,相似度很大的情况下,而label差距越小越好,同时也是对label平滑度的一个衡量

降维的基本原则:如果和在high density区域上是相近的,即相似度很大,则降维后的和也需要很接近,总体来说就是让下面的式子尽可能小
这里的表示与这两点的相似度
如果说在high desity region 是close的,那我们就希望也是相近的。如果两个data point很像,那做完dimension reduction以后距离就很近,反之很小,距离要怎样都可以。
但光有上面这个式子是不够的,假如令所有的z相等,比如令,那上式就会直接停止更新
在semi-supervised中,如果所有label 都设成一样,会使得supervised部分的变得很大,因此lost就会很大,但在这里少了supervised的约束,因此我们需要给一些额外的约束:
这也是Laplacian Eigenmaps名称的由来,我们找的就是Laplacian matrix的特征向量
如果通过拉普拉斯特征映射找到之后再对其利用K-means做聚类,就叫做谱聚类(spectral clustering)

t-SNE,全称为T-distributed Stochastic Neighbor Embedding,t分布随机邻居嵌入
前面的方法只假设了相邻的点要接近,却没有假设不相近的点要分开
所以在MNIST使用LLE会遇到下图的情形,它确实会把同一个class的点都聚集在一起,却没有办法避免不同class的点重叠在一个区域,这就会导致依旧无法区分不同class的现象
COIL-20数据集包含了同一张图片进行旋转之后的不同形态,对其使用LLE降维后得到的结果是,同一个圆圈代表同张图像旋转的不同姿态,但许多圆圈之间存在重叠

做t-SNE同样要降维,把原来的data point x变成low dimension vector z,在原来的分布空间上,我们需要计算所有与之间的相似度
然后需要将其做归一化:,即与的相似度占所有与相关的相似度的比例
将降维到,同样可以计算相似度,并做归一化:

这里的归一化是有必要的,因为我们无法判断在和所在的空间里,与的范围是否是一致的,需要将其映射到一个统一的概率区间。
我们希望找到的投影空间,可以让和的分布越接近越好
所以我们要做的事情就是找一组z,它可以做到,对其他point的distribution跟对其他point的distribution,这样的distribution之间的KL距离越小越好,然后summation over 所有的data point,使得这这个值越小越好。
用于衡量两个分布之间相似度的方法就是KL散度(KL divergence),我们的目标就是让越小越好:
这里简单补充一下KL散度的基本知识
KL 散度,最早是从信息论里演化而来的,所以在介绍 KL 散度之前,我们要先介绍一下信息熵,信息熵的定义如下:
其中表示事件发生的概率,信息熵其实反映的就是要表示一个概率分布所需要的平均信息量
在信息熵的基础上,我们定义KL散度为:
表示的就是概率与概率之间的差异,很显然,KL散度越小,说明概率与概率之间越接近,那么预测的概率分布与真实的概率分布也就越接近
t-SNE会计算所有样本点之间的相似度,运算量会比较大,当在data point比较多的时候跑起来效率会比较低
常见的做法是对原先的空间用类似PCA的方法先做一次降维,然后用t-SNE对这个简单降维空间再做一次更深层次的降维,以期减少运算量。比如说:原来的dimension很大,不会直接从很高的dimension直接做t-SNE,因为这样计算similarity时间会很长,通常会先用PCA做将降维,降到50维,再用t-SNE降到2维,这个是比较常见的做法。
值得注意的是,t-SNE的式子无法对新的样本点进行处理,一旦出现新的,就需要重新跑一遍该算法,所以t-SNE通常不是用来训练模型的,它更适合用于做基于固定数据的可视化。
t-SNE常用于将固定的高维数据可视化到二维平面上。你有一大堆的x是high dimension,你想要它在二维空间的分布是什么样子,你用t-SNE,t-SNE会给你往往不错的结果。
如果根据欧氏距离计算降维前的相似度,往往采用RBF function(Radial Basis Function ) ,这个表达式的好处是,只要两个样本点的欧氏距离稍微大一些,相似度就会下降得很快
在t-SNE之前,有一个方法叫做SNE:dimension reduction以后的space,它选择的measure跟原来的space是一样的。
对t-SNE来说,它在降维后的新空间所采取的相似度算法是与之前不同的,它选取了t-distribution中的一种,即
以下图为例,假设横轴代表了在原先空间上的欧氏距离或者做降维之后在空间上的欧氏距离,红线代表RBF function,是降维前的分布;蓝线代表了t-distribution,是降维后的分布
你会发现,降维前后相似度从RBF function到t-distribution:

也就是说t-SNE可以聚集相似的样本点,同时还会放大不同类别之间的距离,从而使得不同类别之间的分界线非常明显,特别适用于可视化。
下图则是对MNIST和COIL-20先做PCA降维,再做t-SNE降维可视化的结果,t-SNE画出来的图往往长的这样,它会把你的data point 聚集成一群一群的,只要你的data point离的比较远,那做完t-SNE之后,就会强化,变得更远了。

如图为t-SNE的动画。因为这是利用gradient descent 来train的,所以你会看到随着iteration process,点会被分的越来越开。

小结一下,本文主要介绍了三种非线性降维的算法:
文本介绍了自编码器的基本思想,与PCA的联系,从单层编码到多层的变化,在文字搜索和图像搜索上的应用,预训练DNN的基本过程,利用CNN实现自编码器的过程,加噪声的自编码器,利用解码器生成图像等内容
自动编码器的想法是这样子的:我们先去找一个encoder,这个encoder input一个东西(假如说,我们来做NMIST的话,就是input一张digit,它是784维的vector),这个encoder可能就是一个neural network,它的output就是code(这个code远比784维要小的,类似压缩的效果),这个coder代表了原来input一张image compact representation。
但是现在问题是:我们现在做的是Unsupervised learning,你可以找到一大堆的image当做这个NN encoder的input,但是我们不知道任何的output。你要learn 一个network,只有一个input,你没有办法learn它。那没有关系,我们要做另外一件事情:想要learn 一个decoder,decoder做的事情就是:input一个vector,它就通过这个NN decoder,它的output就是一张image。但是你也没有办法train一个NN decoder,因为你只要output,没有input。
这两个network,encoder decoder单独你是没有办法去train它。但是我们可以把它接起来,然后一起train。也就是说: 接一个neural network ,input一张image,中间变成code,再把code变成原来的image。这样你就可以把encoder跟decoder一起学,那你就可以同时学出来了。
Auto-encoder本质上就是一个自我压缩和解压的过程,我们想要获取压缩后的code,它代表了对原始数据的某种紧凑精简的有效表达,即降维结果,这个过程中我们需要:

Encoder和Decoder单独拿出一个都无法进行训练,我们需要把它们连接起来,这样整个神经网络的输入和输出都是我们已有的图像数据,就可以同时对Encoder和Decoder进行训练,而降维后的编码结果就可以从最中间的那层hidden layer中获取
那我们刚才在PCA里面看过非常类似的概念,我们讲过:PCA其实在做的事情是:input一张image x(在刚才的例子里面,我们会让当做input,这边我们把减掉省略掉,省略掉并不会太奇怪,因为通常在做NN的时候,你拿到的data其实会normlize,其实你的data mean是为0,所以就不用再去减掉mean),把x乘以一个weight,通过NN一个layer得到component weight ,乘以matrix 的transpose得到。是根据这些component的reconstruction的结果。
实际上PCA用到的思想与Auto-encoder非常类似,PCA的过程本质上就是按组件拆分,再按组件重构的过程
在PCA中,我们先把均一化后的根据组件分解到更低维度的,然后再将组件权重乘上组件的转置得到重组后的,同样我们期望重构后的与原始的越接近越好

如果把这个过程看作是神经网络,那么原始的就是input layer,重构就是output layer,中间组件分解权重就是hidden layer,在PCA中它是linear的,我们通常又叫它瓶颈层(Bottleneck layer)。你可以用gradient descent来解PCA。
hidden layer的output就是我们要找的那些code。由于经过组件分解降维后的,维数要远比输入输出层来得低,因此hidden layer实际上非常窄,因而有瓶颈层的称呼。
对比于Auto-encoder,从input layer到hidden layer的按组件分解实际上就是编码(encode)过程,从hidden layer到output layer按组件重构实际上就是解码(decode)的过程。
这时候你可能会想,可不可以用更多层hidden layer呢?答案是肯定的
对deep的自编码器来说,实际上就是通过多级编码降维,再经过多级解码还原的过程
此时:

注意到,如果按照PCA的思路,则Encoder的参数需要和Decoder的参数保持一致的对应关系,这样做的好处是,可以节省一半的参数,降低overfitting的概率
但这件事情并不是必要的,实际操作的时候,你完全可以对神经网络用Backpropagation直接train下去,而不用保持编码器和解码器的参数一致
下图给出了Hinton分别采用PCA和Deep Auto-encoder对手写数字进行编码解码后的结果。
original image做PCA,从784维降到30维,然后从30维reconstruction回784维,得到的image差不多,可以看出它是比较模糊的。
如果是用deep encoder的话,784维先扩为1000维,再不断下降,下降到30维(你很难说为什么它会设计成这样子),然后再把它解回来。你会发现,如果用的是deep Auto-encoder的话,它的结果看起来非常的好。

如果将其降到2维平面做可视化,不同颜色代表不同的数字,可以看到

Auto-encoder也可以用在文字处理上,比如说:我们把一篇文章压成一个code。
比如我们要做文字检索,很简单的一个做法是Vector Space Model,把每一篇文章都表示成空间中的一个vector
假设查询者输入了某个词汇,那我们就把该查询词汇也变成空间中的一个点,并计算query和每一篇document之间的内积(inner product)或余弦相似度(cos-similarity)
注:余弦相似度有均一化的效果,可能会得到更好的结果
下图中跟query向量最接近的几个向量的cosine-similarity是最大的,于是可以从这几篇文章中去检索
实际上这个模型的好坏,就取决于从document转化而来的vector的好坏,它是否能够充分表达文章信息
把一个document表示成一个vector,最简单的表示方法是Bag-of-word,维数等于所有词汇的总数,某一维等于1则表示该词汇在这篇文章中出现,此外还可以根据词汇的重要性将其加权;但这个模型是非常weak的,它没有考虑任何Semantics相关的东西,对它来说每个词汇都是相互独立的。

我们可以把它作为Auto-encoder的input,通过降维来抽取有效信息,以获取所需的vector
同样为了可视化,这里将Bag-of-word降维到二维平面上,下图中每个点都代表一篇文章,不同颜色则代表不同的文章类型
我们可以用Auto-encoder让语义被考虑进来 ,举例来说,你learn一个Auto-encoder,它的input就是一个document 或一个query,通过encoder把它压成二维。
每一个点代表一个document,不同颜色代表document属于哪一类。今天要做搜寻的时候,今天输入一个词汇,那你就把那个query也通过这个encoder把它变为一个二维的vector。假设query落在某一类,你就可以知道这个query与哪一类有关,就把document retrieve出来。

在矩阵分解(Matrix Factorization)中,我们介绍了LSA算法,它可以用来寻找每个词汇和每篇文章背后的隐藏关系(vector),在这里我们采用LSA,并使用二维latent vector来表示每篇文章。
Auto-encoder的结果是相当惊人的。则如果用LSA的话,得不到类似的结果。
Auto-encoder同样可以被用在图像检索上
image search最简单的做法就是直接对image query与database中的图片计算pixel的相似度,并挑出最像的图片,但这种方法的效果是不好的,因为单纯的pixel所能够表达的信息太少了。

我们需要使用Auto-encoder对图像进行降维和特征提取,把每一张image变成一个code,然后再code上面去做搜寻,在编码得到的code所在空间做检索。
learn一个Auto-encoder是unsupervised,所以你要多少data都行(supervised是很缺data的,unsupervised是不缺data的)
input一张32*32的image,每一个pixel用RGB来表示(32 * 32 *3),变成8192维,然后dimension reduction变成4096维,最后一直变为256维,你用256维的vector来描述这个image。然后你把这个code再通过另外一个decoder(形状反过来,变成原来的image),它的reconstruction是右上角如图。

这么做的好处如下:
如果你不是在pixel上算相似度,是在code上算相似度的话,你就会得到比较好的结果。举例来说:你是用Jackson当做image的话,你找到的都是人脸,相比之前的结果进步了一些。可能这个image在pixel label上面看起来是不像的,但是你通过很多的hidden layer把它转成code的时候,在那个256维的空间上看起来是像的,可能在投影空间中某一维就代表了人脸的特征,因此能够被检索出来。

在训练神经网络的时候,我们一般都会对如何做参数的initialization比较困扰,预训练(pre-training)是一种寻找比较好的参数initialization的方法,而我们可以用Auto-encoder来做pre-training
以MNIST数据集为例,我们使用的neural network input 784维,第一个hidden layer是1000维,第二个hidden layer是1000维,第三个hidden layer是500维,然后到10维。
我们对每层hidden layer都做一次auto-encoder,使每一层都能够提取到上一层最佳的特征向量
那我做Pre-taining的时候,我先train一个Auto-encoder,这个Auto-encoder input784维,中间有1000维的vector,然后把它变回784维,我期望input 跟output越接近越好。

在做这件事的时候,你要稍微小心一点,我们一般做Auto-encoder的时候,你会希望你的coder要比dimension还要小。比dimension还要大的话,你会遇到的问题是:它突然就不learn了,把784维直接放进去,得到一个接近identity的matrix。
所以你今天发现你的hidden layer比你的input还要大的时候,你要加一个很强的regularization在1000维上,你可以对这1000维的output做L1的regularization,可以希望说:这1000维的output里面,只有某几维是可以有值的,其他维要必须为0。这样你就可以避免Auto-encoder直接把input背起来再输出的问题。总之你今天的code比你input还要大,你要注意这种问题。
首先使input通过一个如上图的Auto-encoder,input784维,code1000维,output784维,learn参数,当该自编码器训练稳定后(它会希望input跟output越接近越好),就把参数fix住。然后将数据集中所有784维的图像都转化为1000维的vector
接下来再让这些1000维的vector通过另外一个Auto-encoder,input1000维,code1000维,output1000维learn参数,当其训练稳定后,再把参数固定住,对数据集再做一次转换

接下来再用转换后的数据集去训练第三个Auto-encoder,input1000维,code500维,output1000维,训练稳定后固定,数据集再次更新转化为500维

此时三个隐藏层的参数、、就是训练整个神经网络时的参数初始值
然后random initialization最后一个隐藏层到输出层之间的参数
再用backpropagation去调整一遍参数,因为、、都已经是很好的weight了,这里只是做微调,因此这个步骤称为Find-tune

pre-training在过去learn一个deep neural network还是很需要的,不过现在neural network不需要pre-training往往都能train的起来。由于现在训练机器的条件比以往更好,因此pre-training并不是必要的,但它也有自己的优势。
如果你今天有很多的unlabeled data,少量的labeled data,你可以用大量的unlabeled data先去把、、learn 好,最后再用labeled data去微调~即可。所以pre-training在大量的unlabeled data时还是有用的。
去噪自编码器的基本思想是,把输入的加上一些噪声(noise)变成,再对依次做编码(encode)和解码(decode),得到还原后的
值得注意的是,一般的自编码器都是让输入输出尽可能接近,但在去噪自编码器中,我们的目标是让解码后的与加噪声之前的越接近越好
这种方法可以增加系统的鲁棒性,因为此时的编码器Encoder不仅仅是在学习如何做编码,它还学习到了如何过滤掉噪声这件事情

收缩自动编码器的基本思想是,在做encode编码的时候,要加上一个约束,它可以使得:当input有变化的时候,对code的影响是被minimize的。
这个描述跟去噪自编码器很像,只不过去噪自编码器的重点在于加了噪声之后依旧可以还原回原先的输入,而收缩自动编码器的重点在于加了噪声之后能够保持编码结果不变。
还有很多non-linear 的 dimension reduction的方法,比如Restricted Boltzmann Machine,它不是NN
和RBM一样,只是看起来比较像NN,但是并不是NN
处理图像通常都会用卷积神经网络CNN,它的基本思想是交替使用卷积层和池化层,让图像越来越小,最终展平,这个过程跟Encoder编码的过程其实是类似的。
理论上要实现自编码器,Decoder只需要做跟Encoder相反的事即可,那对CNN来说,解码的过程也就变成了交替使用去卷积层和去池化层即可

那什么是去卷积层(Deconvolution)和去池化层(Unpooling)呢?
做pooling的时候,假如得到一个4×4的matrix,就把每4个pixel分为一组,从每组中挑一个最大的留下,此时图像就变成了原来的四分之一大小
如果还要做Unpooling,就需要提前记录pooling所挑选的pixel在原图中的位置,下图中用灰色方框标注

然后做Unpooling,就要把当前的matrix放大到原来的四倍,也就是把2×2 matrix里的pixel按照原先记录的位置插入放大后的4×4 matrix中,其余项补0即可。
做完unpooling以后,比较小的image会变得比较大,比如说:原来是14 * 14的image会变成28 *28的image。你会发现说:它就是把原来的14 *14的image做一下扩散,在有些地方补0。
当然这不是唯一的做法,在Keras中,pooling并没有记录原先的位置,做Unpooling的时候就是直接把pixel的值复制四份填充到扩大后的matrix里即可
实际上,Deconvolution就是convolution
这里以一维的卷积为例,假设输入是5维,过滤器(filter)的大小是3
卷积的过程就是每三个相邻的点通过过滤器生成一个新的点,如下图左侧所示
在你的想象中,去卷积的过程应该是每个点都生成三个点,不同的点对生成同一个点的贡献值相加;但实际上,这个过程就相当于在周围补0之后再次做卷积,如下图右侧所示,两个过程是等价的
卷积和去卷积的过程中,不同点在于,去卷积需要补零且过滤器的weight与卷积是相反的:
因此在实践中,做Deconvolution的时候直接对模型加卷积层即可

在之前介绍的自编码器中,输入都是一个固定长度的vector,但类似文章、语音等信息实际上不应该单纯被表示为vector,那会丢失很多前后联系的信息。比如说语音(一段声音讯号有长有短),文章(你可能用bag-of-word变成一个vector,但是你会失去词汇和词汇之间的前后关系,是不好的)
Seq2Seq就是为了解决这个问题提出的,具体内容在RNN部分已经介绍
在用自编码器的时候,通常是获取Encoder之后的code作为降维结果,但实际上Decoder也是有作用的,我们可以拿它来生成新的东西
以MNIST为例,训练好Encoder之后,取出其中的Decoder,输入一个随机的code,就可以生成一张图像。
把每一张28×28维的image,通过hidden layer,把它project到2维,2维再通过一个hidden layer解回原来的image。在Encoder的部分,2维的vector画出来如下图左,不同颜色的点代表不同的数字。
然后在红色方框中,等间隔的挑选2维向量丢进Decoder中,就会生成许多数字的图像。这些2维的vector,它不见得是某个原来的image就是对应的vector。我们发现在红框内,等距离的做sample,得到的结果如下图右。在没有image对应的位置,画出的图像怪怪的。

此外,我们还可以对code加L2 regularization,以限制code分布的范围集中在0附近,此时就可以直接以0为中心去随机采取样本点,再通过Decoder生成图像。
观察生成的数字图像,可以发现这两个dimension是有意义的,横轴的维度表示是否含有圆圈,纵轴的维度表示是否倾斜。

Auto-encoder主要包含一个编码器(Encoder)和一个解码器(Decoder),通常它们使用的都是神经网络。Encoder接收一张图像(或是其他类型的数据,这里以图像为例)输出一个vector,它也可称为Embedding、Latent Representation或Latent code,它是关于输入图像的表示;然后将vector输入到Decoder中就可以得到重建后的图像,希望它和输入图像越接近越好,即最小化重建误差(reconstruction error),误差项通常使用的平方误差。
An embedding should represent the object.
最直观的想法是它应该包含了关于输入的关键信息,从中我们就可以大致知道输入是什么样的。
除了使用重建误差来驱动模型训练外,可以使用其他的方式来衡量Encoder是否学到了关于输入的重要表征吗?
假设我们现在有两类动漫人物的图像,一类是三九,一类是凉宫春日。如果将三九的图像丢给Encoder后,它就会给出一个蓝色的Embedding;如果Encoder接收的是凉宫春日的图像,它就会给出一个黄色的Embedding。那么除了Encoder之外,还有一个Discriminator(可以看作Binary Classifier),它接收图像和Embedding,然后给出一个结果表示它们是否是两两对应的。
如果是三九和蓝色的Embedding、凉宫春日和黄色的Embedding,那么Discriminator给出的就是YES;如果它们彼此交换一下,Discriminator给出的就应该是NO。

借助GAN的思想,我们用来表述Discriminator,希望通过训练最小化D的损失函数 ,得到最小的损失值。如果 的值比较小,就认为Encoder得到的Embedding很有代表性;相反 的值很大时,就认为得到的Embedding不具有代表性。

如果用表示Encoder,Train the encoder 𝜃 and discriminator 𝜙 to minimize ,即 ,这样的方法也称为Deep InfoMax(DIM)。这个和training encoder and decoder to minimize reconstruction error的思想其实是差不多的。
Typical auto-encoder is a special case。Discriminator接收一个图像和vector的组合,然后给出一个判断它们是否是配对的分数。在Discriminator的内部先使用Decoder来解码vector生成一个重建的图像,然后和输入图像相减,得到score。只不过这种情况下不考虑negative,只判断有多相似。

Skip thought就是根据中间句来预测上下句。模型在大量的文档数据上训练结束后,Encoder接收一个句子,然后给出输入句子的上一句和下一句是什么。这个模型训练过程和训练word embedding很像,因为训练word embedding的时候有这么一个原则,就是两个词的上下文很像的时候,这两个词的embedding就会很接近。换到句子的模型上,如果两个句子的上下文很像,那么这两个句子的embedding就应该很接近。
这个东西多少钱?答:10元;这个东西多贵?答:10元。发现答案一样,所以问句的embedding是很接近的。
由于Skip thought要训练encoder和decoder,训练速度比较慢,因此有出现一个改进版本Quick thought,顾名思义就是训练速度上很快。
Quick thought不使用Decoder,而是使用一个辅助的分类器。它将当前的句子、当前句子的下一句和一些随机采样得到的句子分别送到Encoder中得到对应的Embedding,然后将它们丢给分类器。因为当前的句子的Embedding和它下一句的Embedding应该是越接近越好,而它和随机采样句子的Embedding应该差别越大越好,因此分类器应该可以判断出哪一个Embedding代表的是当前句子的下一句。

这个模型和Quick thought的思想是很像的,它接收一段序列数据,得到Embedding,然后用它预测接下来数据的Embedding。模型结构如下所示,具体内容可见原论文。

An object contains multiple aspect information

现在我们只用一个向量来表示一个object,我们是无法知道向量的哪些维度包含哪些信息,例如哪些维度包含内容信息,哪些包含讲话人信息等。也就是说这些信息是交织在一起的,我们希望模型可以帮我们把这些信息disentangle开来。
我们以声音讯号为例,假设通过Encoder得到的Embedding是一个100维 的向量,它只包含内容和讲话者身份两种信息。我们希望经过不断的训练,它的前50维代表内容信息,后50维代表讲话者的身份信息。可以用1个Encoder,也可以训练两个encoder分别抽取不同内容,然后把两个部分拼接起来,才能还原原来的内容。

The same sentence has different impact when it is said by different people.



一种方法就是使用GAN的思想,我们在Encoder-Decoder架构中引入一个Classifier,通过Embedding某个具体的部分判断讲话者身份,通过不断地训练,希望Encoder得到的Embedding可以骗过Classifier,就是要使得不能让Classifier分辨出语者的性别,那么那个具体的部分就不包含讲话者的信息。
在实作过程中,通常是利用GAN来完成这个过程,也就是把Encoder看做Generator,把Classifier看做Discriminator。Speaker classifier and encoder are learned iteratively.
使用两个Encoder来分别得到内容信息和讲话者身份信息的Embedding,在Encoder中使用instance normalization,然后将得到的两个Embedding结合起来送入Decoder重建输入数据,除了将两个Embedding直接组合起来的方式,还可以在Decoder中使用Adaptive instance normalization。


通常情况下,Encoder输出的Embedding都是连续值的向量,但如果可以将其转换为离散值的向量,例如one-hot向量或是binary向量,我们就可以更加方便的解读Embedding的哪一部分表示什么信息。
当然此时不能直接使用反向传播来训练模型,一种方式就是用强化学习来进行训练。
当然,上面两个离散向量的模型比较起来,个人觉得Binary模型要好,原因有两点:同样的类别Binary需要的参数量要比独热编码少,例如1024个类别Binary只需要10维即可,独热需要1024维;使用Binary模型可以处理在训练数据中未出现过的类别。
基于这样的想法就出现了一种方法叫VQVAE,它引入了一个Codebook(内容是学出来的)。先用Encoder抽取为连续型的vector;再用vector与Codebook中的离散变量进行相似度计算,哪一个和输入更像,就将其丢给Decoder重建输入。

上面的模型中,如果输入的是语音信号,那么不是Discrete的语者信息和噪音信息会被过滤掉,比较容易保留去辨识的内容和资讯。因为上面的Codebook中保存的是离散变量,而声音里面有关文字的内容信息是一个个的token,是容易用离散向量来表示的,其他不是Discrete的信息会被过滤掉。
seq2seq2seq auto-encoder.
Using a sequence of words as latent representation.
一篇文章经过encoder得到一串文字,然后这串文字再通过decoder还原回文章。
但是这个机器抽取出的sequence是看不懂的,是机器自己的暗号。

可以采用GAN的概念,训练一个Discriminator,判断是否是人写的句子。使得中间的seq可读。

不能微分,实际上用RL train encoder和decoder,loss当作reward。

More than minimizing reconstruction error
More interpretable embedding
最早的词表示方法。它就是one-hot encoding 没什么好说的,就是说如果词典中有N个词,就用N维向量表示每个词,向量中只有一个位置是1,其余位置都是0。但是这么做词汇之间的关联没有考虑。
根据词的类型划分,但是这种方法还是太粗糙了,举举例说dog、cat和bird都是动物,它们应该是同类。但是动物之间也是有区别的,如dog和cat是哺乳类动物,和鸟类还是有些区别的。
有点像是soft 的word class,我们用一个向量来表示一个单词,向量的每一个维度表示某种意思,相近的词汇距离较近,如cat和dog。
Have you paid that money to the bank yet ?
It is safest to deposit your money in the bank.
The victim was found lying dead on the river bank.
They stood on the river bank to fish.
The four word tokens have the same word type.
In typical word embedding, each word type has an embedding.
bank一词在上述前两个句子与后两个句子中的token是不一样的,但是type是一样的。也就是说同样的词有存在不用语义的情况,而词嵌入会为同一个词只唯一确定一个embedding。
那我们能不能标记一词多义的形式呢?可以尝试的解决方案是为bank这个词设置2个不同的embedding,但是确定一个词有几个词义是困难的,可以参看以下句子:
The hospital has its own blood bank.
The third sense or not?下个句子中的bank又有了不同的词义,这个词义可以看做一个新的词义,也可以看做与“银行”词义相同,因此机械地确定一个词有几个词义是困难的,因为很多词的意义是微妙的。
此时我们需要根据上下文来计算对应单词的embedding结果,这种技术称之为Contextualized Word Embedding(语境词嵌入) 。
ELMO是一个RNN-based Language Model,训练的方法就是找一大堆的句子,也不需要做标注,然后做上图所示的训练。
RNN-based Language Model 的训练过程就是不断学习预测下一个单词是什么。举例来说,你要训练模型输出“潮水退了就知道谁没穿裤子”,你教model,如果看到一个开始符号
我们做了正反双向的训练,最终的word embedding 是把正向的RNN 得到的token embedding 和反向RNN 得到的token embedding 接起来作为最终的Contextualized Word Embedding 。

该过程也是可以deep的,如下图的网络结构,每一个隐藏层都会输出一个词的embedding,它们全部都会被使用到。

ELMO会将每个词输出多个embedding,这里我们假设LSTM叠两层。ELMO会用做weighted sum,weight是根据你做的下游任务训练出来的,下游任务就是说用EMLO做SRL(Sematic Role Labeling 语义角色标注)、Coref(Coreference resolution 共指解析)、SNLI(Stanford Natural Language Inference 自然语言推理)、SQuAD(Stanford Question Answering Dataset) 、SST-5(5分类情感分析数据集)等等。
具体来说,你要先train好EMLO,得到每个token 对应的多个embedding,然后决定你要做什么task,然后在下游task 的model 中学习weight 和的值。
原始ELMO的paper 中给出了图中的实验结果,Token是说没有做Contextualized Embedding之前的原始向量,LSTM-1、LSTM-2是EMLO的两层得到的embedding,然后根据下游5个task 学出来的weight 的比重情况。我们可以看出Coref 和SQuAD 这两个任务比较看重LSTM-1抽出的embedding,而其他task 都比较平均的看了三个输入。

BERT = Encoder of Transformer
BERT其实就是Transformer的Encoder,可以从大量没有注释的文本中学习
BERT会输入一些词的序列然后输出每个词的一个embedding。
需要注意,实际操作中如果训练中文,应该以中文的字作为输入。因为中文的词语很难穷举,但字的穷举相对容易,常用汉字约4000个左右,而词的数量非常多,使用词作为输入可能导致输入向量维度非常高(one-hot),所以也许使用字作为基本单位更好。
paper上提及的BERT的训练方法有两种,Masked LM 和Next Sentence Prediction 。
Masked LM这种训练方式指的是在词序列中每个词汇有15%的机率被一个特殊的token[MASK]遮盖掉,得到被遮盖掉的词对应输出的embedding后,使用一个Linear Multi-class Classifier来预测被遮盖掉的词是哪一个,由于Linear Multi-class Classifier的能力很弱,所以训练得到的embedding会是一个非常好的表示。
BERT的embedding是什么样子的呢?如果两个词填在同一个地方没有违和感,那它们就有类似的embedding,代表他们的语义是类似的。

给BERT两个句子,然后判断这两个句子是不是应该接在一起。
具体做法是,[SEP]符号告诉BERT句子交接的地方在哪里,[CLS]这个符号通常放在句子开头,将其通过BERT得到的embedding 输入到简单的Linear Binary Classifier中,Linear Binary Classifier 判断当前这个两个句子是不是应该接在一起。
你可能会疑惑[CLS]难道不应该放在句末,让BERT看完整个句子再做判断吗?
BERT里面一般用的是Transformer的Encoder,也就是说它做的是self-attention,self-attention layer 不受位置的影响,它会看完整个句子,所以一个token放在句子的开头或者结尾是没有差别的。
上述两个方法中,Linear classifier 是和BERT一起训练的。
两个方法在文献上是同时使用的,让BERT的输出去解这两个任务的时候会得到最好的训练效果。

你可以把BERT当作一个抽embedding 的工具,抽出embedding 以后去做别的task。
但是在BERT的paper中是把BERT和down stream task 一起做训练。
输入一个sentence 输出一个class ,有代表性的任务有情感分析,文章分类等。
以句子情感分析为例,你找一堆带有情感标签的句子,丢给BERT,再句子开头设一个判断情感的符号[CLS],把这个符号通过BERT的输出丢给一个线性分类器做情感分类。线性分类器是随机初始化参数,再用你的训练资料train 的,这个过程中也可以对BRET进行fine-tune ,也可以fix住BRET的参数。

输入:一个句子;输出:词的类别;例子:槽位填充
将句子输入到BERT,将每个token对应输出的embedding输入到一个线性分类器中进行分类。线性分类器要从头开始训练,BERT的参数只需要微调即可。

输入:两个句子;输出:类别;例子:自然语言推理
可以将两个句子输入到BERT,两个句子之间添加一个token[SEP],这两个句子分别是premise和hypothesis,第一个token设置为[CLS]表示句子的分类。
将第一个token对应输出的embedding输入到一个线性分类器中进行分类,分类结果代表在该假设下该推断是true (entailment), false (contradiction), or undetermined (neutral) 。线性分类器要从头开始训练,BERT的参数只需要微调即可。

BERT还可以用来做Extraction-based Question Answering,也就是阅读理解,如下图所示,给出一篇文章然后提问一个问题,BERT就会给出答案,前提是答案在文中出现。
模型输入Document D 有N个单词,Query Q有M个单词,模型输出答案在文中的起始位置和结束位置:s和e。举例来说,图中第一个问题的答案是gravity,是Document 中第17个单词;第三个问题的答案是within a cloud,是Document 中第77到第79个单词。
怎么用BERT解这个问题呢?

通过BERT后,Document 中每个词都会有一个向量表示,然后你再去learn 两个向量,得到图中红色和蓝色向量,这两个向量的维度和BERT的输出向量相同,红色向量和Document 中的词汇做点积得到一堆数值,把这些数值做softmax 最大值的位置就是s,同样的蓝色的向量做相同的运算,得到e:如果e落在s的前面,有可能就是无法回答的问题。
这个训练方法,你需要label很多data,每个问题的答案都需要给出在文中的位置。两个向量是从头开始学出来的,BERT只要fine-tune就好 。


ERNIE是类似BERT的模型,是专门为中文设计的,如果使用BERT的第一种训练方式时,一次只会盖掉一个字,对于BERT来说是非常好猜到的,因此ERNIE会一次盖掉中文的一个词。

思考一下BERT每一层都在做什么,列出两个reference 给大家做参考。
假如我们的BERT有24层,单纯用BERT做embedding,用得到的词向量做下游任务。down stream task有POS、Consts等等,实验把BERT的每一层的Contextualized Embedding 抽出来做weighted sum,然后通过下游任务learn 出weight,看最后learn出的weight 的情况,就可以知道这个任务更需要那些层的vector 。
图中右侧蓝色的柱状图,代表通过不同任务learn出的BERT各层的weight ,POS是做词性标注任务,会更依赖11-13层;Coref是做分析代词指代,会更依赖BERT高层的向量(17-20层);而SRL语义角色标注就比较平均地依赖各层抽出的信息。前三个任务都是文法相关的,因此更需要前面几层。若任务更困难,通常会需要比较深层抽出的embedding。

用104种语言的文本资料给BERT学习,虽然BERT没看过这些语言之间的翻译,但是它看过104种语言的文本资料以后,它似乎自动学会了不同语言之间的对应关系。
所以,如果你现在要用这个预训练好的BERT去做文章分类,你只要给他英文文章分类的label data set,它学完之后,竟然可以直接去做中文文章的分类。

GPT-2是OpenAI 做的,OpenAI 用GPT-2 做了一个续写故事的例子,他们给机器看第一段,后面都是机器脑补出来的。机器生成的段落中提到了独角兽和安第斯山,所以现在都拿独角兽和安第斯山来隐喻GPT。
OpenAI担心GPT-2最大的模型过于强大,可能会被用来产生假新闻这种事上,所以只发布了GPT-2的小模型。
有人用GPT-2的公开模型做了一个在线demo。
我们上面说BERT是Transformer 的Encoder ,GPT其实是Transformer 的Decoder 。
GPT和一般的Language Model 做的事情一样,就是你给他一些词汇,它预测接下来的词汇。举例来说,如上图所示,把“潮水的”q拿出来做self-attention,然后做softmax 产生 ,再分别和v做相乘求和得到b,self-attention 可以有很多层(b是vector,上面还可以再接self-attention layer),通过很多层以后要预测“退了”这个词汇。

预测出“退了”以后,把“退了”拿下来,做同样的计算,预测“就”这个词汇,如此往复。

GPT-2是一个巨大的预训练模型,它可以在没有更多训练资料的情况下做以下任务:
BERT也可以做Reading Comprehension,但是BERT需要新的训练资料train 线性分类器,对BERT本身进行微调。而GPT可以在没有训练资料的情况下做这个任务。
给GPT-2一段文章,给出一个问题,再写一个A:,他就会尝试做出回答。下图是GPT-2在CoQA上的结果,最大的GPT-2可以和DrQA达到相同的效果,不要忘了GPT-2在这个任务上是zero-shot learning ,从来没有人教过它做QA 。
给出一段文章加一个too long don’t read 的缩写"TL;DR:" 就会尝试总结这段文字。
以上图所示的形式给出 一段英文=对应的法语,这样的例子,然后机器就知道要给出第三句英文的法语翻译。
其实后两个任务效果其实不是很好,Summarization就像是随机生成的句子一样。


有人分析了一下GTP-2的attention做的事情是什么。
上图右侧的两列,GPT-2中左列词汇是下一层的结果,右列是前一层需要被attention的对象,我们可以观察到,She 是通过nurse attention 出来的,He是通过doctor attention 出来的,所以机器学到了某些词汇是和性别有关系的(虽然它大概不知道性别是什么)。
上图左侧,是对不同层的不同head 做一下分析,你会发现一个现象,很多不同的词汇都要attend 到第一个词汇。一个可能的原因是,如果机器不知道应该attend 到哪里,或者说不需要attend 的时候就attend 在第一个词汇。如果真是这样的话,以后我们未来在做这种model 的时候可以设一个特别的token,当机器不知道要attend到哪里的时候就attend到这个特殊token上。
异常探测就是要让机器知道它不知道这件事
异常侦测的问题通常formulation成这样,假设我们现在有一堆训练数据(),(在这门课里面,我们通常用上标来表示一个完整的东西,用下标来表示一个完整东西的其中一部分)。我们现在要找到一个function,这个function要做的事情是:检测输入x的时,决定现在输入的x到底跟我们的训练数据是相似还是不相似的。
我们一直在用Anoamly这个词汇,可能会让某些同学觉得机器在做Anoamly Detector都是要Detector不好的结果,因为异常这个词汇显然通常代表的是负面意思。其实Anoramly Detector并不一定是找不好的结果,只是找跟训练数据不一样的数据。所以我们找出结果不见得是异常的数据,你会发现Anoamly Detector在不同的领域里面有不同名字。有时候我们会叫它为“Outlier Detector, Novelty Detector, Exceprions Detector”
总之我们要找的是跟训练数据不一样的数据,但至于什么叫做similar,这就是Anoamly Detector需要探讨的问题。不同的方法就有不同的方式来定义什么叫做“像”、什么叫做“不像”。

这里我要强调一下什么叫做异常,机器到底要看到什么就是Anormaly。其实是取决你提供给机器什么样的训练数据。
假设你提供了很多的雷丘作为训练数据,皮卡丘就是异常的。若你提供了很多的皮卡丘作为训练数据,雷丘就是异常的。若你提供很多的宝可梦作为训练数据,这时数码宝贝就是异常的。
异常侦测有很多的应用,你可以应用到诈欺侦测(Fraud Detection)。训练数据是正常的刷卡行为,收集很多的交易记录,这些交易记录视为正常的交易行为,若今天有一笔新的交易记录,就可以用异常检测的技术来侦测这笔交易记录是否有盗刷的行为。(正常的交易金额比较小,频率比较低,若短时间内有非常多的高额消费,这可能是异常行为)
异常侦测还可以应用到网络系统的入侵侦测,训练数据是正常连线。若有一个新的连线,你希望用Anoramly Detection让机器自动决定这个新的连线是否为攻击行为
异常侦测还可以应用到医疗(癌细胞的侦测),训练数据是正常细胞。若给一个新的细胞,让机器自动决定这个细胞是否为癌细胞。
我们咋样去做异常侦测这件事呢?很直觉的想法就是:若我们现在可以收集到很多正常的资料,我们可以收集到很多异常的资料。我们可以将normal data当做一个Class(Class1),anomaly data当做另外一个Class(Class2)。我们已经学过了binary classification,这时只需要训练一个binary classifier,然后就结束了。
这个问题其实并没有那么简单,因为不太容易把异常侦测视为一个binary classification的问题。为什么这样说呢?
假设现在有一笔正常的训练数据是宝可梦,只要不是宝可梦就视为是异常的数据,这样不只是数码宝贝是异常数据,凉宫春日也是异常数据,茶壶也是异常的数据。不属于宝可梦的数据太多了,不可能穷举所有不是宝可梦的数据。根本没有办法知道整个异常的数据(Class2)是怎样的,所以不应该将异常的数据视为一个类别,应为它的变化太大了。这是第一个不能将异常侦测视为二元分类的原因。
第二个原因是:很多情况下不太容易收集到异常的资料,收集正常的资料往往比较容易,收集异常的资料往往比较困难。对于刚才的诈欺侦测例子而言,你可以想象多数的交易通常都是正常的,很难找到异常的交易。这样就造成异常侦测不是一个单纯的二元分类问题,需要想其它的方法,它是一个独立的研究主题,仍然是一个尚待研究的问题。
接下来对异常侦测做一个简单的分类
一类,是不只有训练数据 ,同时这些数据还具有label 。 用这样的数据集可以train出一个classifier,让机器通过学习这些样本,以预测出新来的样本的label,但是我们希望分类器有能力知道新给样本不属于原本的训练数据的任何类别,它会给新样本贴上“unknown”的标签。训练classifier 可以用generative model、logistic regression、deep learning等方法,你可以从中挑一个自己喜欢的算法train 出一个classifier 。
上述的这种类型的任务,train出的classifier 具有看到不知道的数据会标上这是未知物的能力,这算是异常检测的其中一种,又叫做Open-set Recognition。我们希望做分类的时候模型是open 的,它可以辨识它没看过的东西,没看过的东西它就贴一个“unknown”的标签。
另一类,所有训练数据都是没有label 的,这时你只能根据现有资料的特征去判断,新给的样本跟原先的样本集是否相像。这种类型的数据又分成两种情况:
情况二是更常见的,对于刚才的诈欺检测的例子而言,银行收集了大量的交易记录,它把所有的交易记录都当做是正常的,然后告诉机器这是正常交易记录,然后希望机器可以借此检测出异常的交易。但所谓的正常的交易记录可能混杂了异常的交易,只是银行在收集资料的时候不知道这件事。所以我们更多遇到的是:手上有训练样本,但我没有办法保证所有的训练样本都是正常的,可能有非常少量的训练样本是异常的。
现在给定的例子是要侦测一个人物是不是来自辛普森家庭,可以看出是来自辛普森家庭(辛普森家庭的人有很明显的特征:脸是黄色的,嘴巴像似鸭子),同时也可以看出凉宫春日显然不是来自辛普森家庭。
假设我们收集的辛普森家庭的人物都具有标注(霸子,丽莎,荷马,美枝),有了这些训练资料以后就可以训练出一个辛普森家庭成员的分类器。我们就可以给分类器看一张照片,它就可以判断这个照片中的人物是辛普森家庭里面的哪个人物。
现在我们想做的事情是根据这个分类器来进行异常侦测,判断这个人物是否来自辛普森家庭。
我们原本是使用分类器来进行分类,现在希望分类器不仅可以来自分类,还会输出一个数值,这个数值代表信心分数(Confidence score ),然后根据信心分数做异常侦测这件事情。
定义一个阈值称之为,若信心分数大于就说明是来自于辛普森家庭。若信心分数小于就说明不是来自于辛普森家庭
咋样可以得到信心分数呢?若我们将图片输入辛普森家庭的分类器中,若分类器非常的肯定这个图片到底是谁,输出的信心分数就会非常的高。当我们将图片输入分类器时,分类器的输出是一个机率分布(distribution),所以将一张图片输入分类器时,分类器会给事先设定的标签一个分数。
如图所示,将“霸子”图片输入分类器,分类器就会给“霸子”一个很高的分数。
但你若给它一张很奇怪的图片(凉宫春日),这时输出的分数会特别的平均,代表机器是没有信心的。若输出特别平均,那这张图片就是异常的图片
刚才讲的都是定性的分析,现在需要将定性分析的结果化为信心分数。
一个非常直觉的方法就是将分类器的分布中最高数值作为信心分数,所以上面那张图输出的信心分数为0.97(霸子),下面那张图输出的信心分数为0.26(凉宫春日)
根据信心分数来进行异常检测不是唯一的方法,因为输出的是distribution,那么就可以计算entropy。entropy越大就代表输出越平均,代表机器没有办法去肯定输出的图片是哪个类别,表示输出的信心分数是比较低。总之我们有不同的方法根据分类器决定它的信心分数。
现在我输入一张训练资料没有的图片(荷马),分类器输出荷马的信心分数是1.00;输入霸子的图片,分类器输出霸子的信心分数为0.81,输出郭董的信心分数为0.12;输入三玖的图片,分类器输出柯阿三的信心分数为0.34,输出陈趾鹹的信心分数为0.31,输出鲁肉王的信心分数为0.10。
以上都是动漫人物,现在输入一张真人的图片,分类器输出柯阿三的信心分数为0.63,输出宅神的信心分数为0.08,输出小丑阿基的信心分数为0.04,输出孔龙金的信心分数为0.03。
我们可以发现,如果输入的是辛普森家庭的人物,分类器输出比较高信心分数。如果输入不是辛普森家庭的任务,分类器输出的信心分数是比较低。
但是也有一些例外,比如输入凉宫春日的图片,分类器输出柯阿三的信心分数为0.99。
若输入大量的训练资料输入至分类器中,输出的信心分数分布如图所示。几乎所有的辛普家庭的人物输入分类器中,无论是否辨识有错都会给出一个较高的信心分数。
但还是发现若辨识有错误会得到较低的信心分数,如图所示的红色点就是辨识错误图片的信心分数的分布。蓝色区域分布相较于红色区域集中在1的地方,有很高的信心分数认为是辛普森家庭的人物。

若输入其它动画的人物图片,其分类器输出的信心分数如题所示,我们会发现有1/10的图片的信心分数比较高(不是辛普森家庭的人物,但给了比较高的分数),多数的图片得到的信心分数比较低。
刚才是比较直观的给出了一个信心分数,你可能会觉得这种方法会让你觉得非常弱,不过刚才那种非常简单的方法其实在实作上往往还可以有不错的结果。
若你要做异常侦测的问题,现在有一个分类器,这应该是你第一个要尝试的baseline。虽然很简单,但不见得结果表现会很差。
也有更好的方法,比如你训练一个neuron network时,可以直接让neuron network输出信心分数,具体细节可参考:Terrance DeVries, Graham W. Taylor, Learning Confidence for Out-of-Distribution Detection in Neural Networks, arXiv, 2018
我们有大量的训练资料,且训练资料具有标注(辛普森家庭哪个人物),因此我们可以训练一个分类器。不管用什么方法,可以从分类器中得到对所有图片的信心分数。然后就根据信心分数建立异常侦测的系统,若信心分数高于某个阀值(threshold)时就认为是正常,若低于某个阀值(threshold)时就认为是异常。
在之前的课程中已经讲了Dev Set的概念,需要根据Dev Set调整模型的超参数(hyperparameter),才不会过拟合。
在异常侦测的任务里面我们的Dev Set,不仅是需要大量的images,还需要被标注这些图片是来自辛普森家庭的人物还是不是来自辛普森家庭的人物。需要强调的是在训练时所有的资料都是来自辛普森家庭的人物,标签是来自辛普森家庭的哪一个人物。
但是我们要做Dev Set时,Dev Set要模仿测试数据集(testing Set),Dev Set要的并不是一张图片(辛普森家庭的哪一个人物),而应该是:辛普森家庭的人物和不是辛普森家庭的人物。
有了Dev Set以后,我们就可以把我们异常侦测的系统用在Dev Set,然后计算异常侦测系统在Dev Set上的performance是多少。你能够在Dev Set衡量一个异常侦测系统的performance以后,你就可以用Dev Set调整阀值(threshold),找出让最好的阀值(threshold)。
决定超参数以后(hyperparameters),就有了一个异常侦测的系统,你就可以让它上线。输入一张图片,系统就会决定是不是辛普森家庭的人物。
接下里要讲的是:如何计算一个异常侦测系统的性能好坏?现在有100张辛普森家庭人物的图片和5张不是辛普森家庭人物的图片。如图所示,辛普森家庭是用蓝色来进行表示,你会发现基本都集中在高分的区域。5张不是辛普森家庭的图片用红色来表示。
你会发现图的左边有一个辛普森家庭人物的分数是非常低的,在异常侦测时机器显然会在这里犯一个错误,认为它不是辛普森家庭人物,这张图片是辛普森家庭的老爷爷。
第一个图片是看起来像安娜贝尔的初音,第二张图片是小樱,第三张图片也是小樱,第四张图是凉宫春日,第五张图是魔法少女。我们会发现这个魔法少女的信心分数非常的高(0.998),事实上在这个bar中有百分之七十五的信心分数都高于0.998,多数辛普森家庭人物得到的信心分数都是1。
很多人在实作时,发现这张异常的图片却给到了0.998很高的分数。但你发现那些正常的图片往往得到更高的分数。虽然这些异常的图片可以得到很高的分数,但如果没有正常图片的分数那么高,还是可以得到较好的异常侦测的结果。

我们咋样来评估一个异常侦测系统的好坏呢?我们知道异常侦测其实是一个二元分类(binary classification)的问题。在二元分类中我们都是用正确率来衡量一个系统的好坏,但是在异常侦测中正确率并不是一个好的评估系统的指标。你可能会发现一个系统很可能有很高的正确率,但其实这个系统什么事都没有做。为什么这样呢?因为在异常侦测的问题中正常的数据和异常的数据之间的比例是非常悬殊的。在这个例子里面,我们使用了正常的图片有一百张,异常的图片有五张。
通常来说正常的资料和异常的资料之间的比例是非常悬殊的,所以只用准确率衡量系统的好坏会得到非常奇怪的结果的。
在如图所示的例子中,我们认为有一个异常侦测的系统,它的设为0.3以下。以上认为是正常的,以下认为是异常的。这时你会发现这个系统的正确率是95.2%,由于异常资料很少,所以正确率仍然是很高的。所以异常侦测问题中不会用正确率来直接当做评估指标。
首先我们要知道在异常侦测中有两种错误:一种错误是异常的资料被判断为正常的资料,另外一种是正常的资料被判为异常的资料。假设我们将设为0.5(0.5以上认为是正常的资料,0.5以下认为是异常的资料),这时就可以计算机器在这两种错误上分别犯了多少错误。
对于所有异常的资料而言,有一笔资料被侦测出来,其余四笔资料没有被侦测为异常的资料。对于所有正常的资料而言,只有一笔资料被判断为异常的资料,其余的九十九笔资料被判断为正常的资料。这时我们会说机器有一个false alarm(正常的资料被判断为异常的资料)错误,有四个missing(异常的资料却没有被侦测出来)错误。
若我们将阀值(threshold)切在比0.8稍高的部分,这时会发现在五张异常的图片中,其中有两张认为是异常的图片,其余三种被判断为正常的图片;在一百张正确的图片中,其中有六张图片被认为是异常的图片,其余九十四张图片被判断为正常的图片。
哪一个系统比较好呢?其实你是很难回答这个问题。有人可能会很直觉的认为:当阀值为0.5时有五个错误,阀值为0.8时有九个错误,所以认为左边的系统好,右边的系统差。
但其实一个系统是好还是坏,取决你觉得false alarm比较严重还是missing比较严重。

所以你在做异常侦测时,可能有一个Cost Table告诉你每一种错误有多大的Cost。若没有侦测到资料就扣一分,若将正确的资料被误差为错误的资料就扣100分。若你是使用这样的Cost来衡量系统的话,左边的系统会被扣104分,右边的系统会被扣603分。所以你会认为左边的系统较好。若Cost Table为Cost Table B 时,异常的资料没有被侦测出来就扣100分,将正常的资料被误判为错误的资料就扣1分,计算出来的结果会很不一样。
在不同的情景下、不同的任务,其实有不同的Cost Table:假设你要做癌症检测,你可能就会比较倾向想要用右边的Cost Table。因为一个人没有癌症却被误判为有癌症,顶多就是心情不好,但是还可以接受。若一个人其实有癌症,但没有检查出来,这时是非常严重的,这时的Cost也是非常的高。
这些Cost要给出来,其实是要问你现在是什么样的任务,根据不同的任务有不同的Cost Table。所以根据右边的Cost Table,左边的Cost为401分,右边的Cost为306分,所以这时右边的系统较好。
其实还有很多衡量异常检测系统的指标,有一个常用的指标为AUC(Area under ROC curve)。若使用这种衡量的方式,你就不需要决定阀值(threshold),而是看你将测试集的结果做一个排序(高分至低分),根据这个排序来决定这个系统好还是不好。
如果我们直接用一个分类器来侦测输入的资料是不是异常的,这并不是一种很弱的方法,但是有时候无法给你一个perfect的结果,我们用这个图来说明用classifier做异常侦测时有可能会遇到的问题。
假设现在做一个猫和狗的分类器,将属于的一类放在一边,属于狗的一类放在一边。若输入一笔资料即没有猫的特征也没有狗的特征,机器不知道该放在哪一边,就可能放在这个boundary上,得到的信息分数就比较低,你就知道这些资料是异常的。
你有可能会遇到这样的状况:有些资料会比猫更像猫(老虎),比狗还像狗(狼)。机器在判断猫和狗时是抓一些猫的特征跟狗的特征,也许老虎在猫的特征上会更强烈,狼在狗的特征上会更强烈。对于机器来说虽然有些资料在训练时没有看过(异常),但是它有非常强的特征会给分类器很大的信心看到某一种类别。
在解决这个问题之前我想说辛普森家庭人物脸都是黄的,如果用侦测辛普森家庭人物的classifier进行侦测时,会不会看到黄脸的人信心分数会不会暴增呢?所以将三玖的脸涂黄,结果侦测为是宅神,信心分数为0.82;若再将其头发涂黄,结果侦测为丽莎,信心分数为1.00。若将我的脸涂黄,结果侦测为丽莎,信心分数为0.88。
当然有些方法可以解这个问题,这里列一些文献给大家进行参考。其中的一个解决方法是:假设我们可以收集到一些异常的资料,我们可以教机器看到正常资料时不要只学会分类这件事情,要学会一边做分类一边看到正常的资料信心分数就高,看到异常的资料就要给出低的信心分数。
但是会遇到的问题是:很多时候不容易收集到异常的数据。有人就想出了一个神奇的解决方法就是:既然收集不到异常的资料,那我们就通过Generative Model来生成异常的资料。这样你可能遇到的问题是:若生成的资料太像正常的资料,那这样就不是我们所需要的。所以还要做一些特别的constraint,让生成的资料有点像正常的资料,但是又跟正常的资料又没有很像。接下来就可以使用上面的方法来训练你的classifier。
接下来我们再讲第二个例子,在第二个例子中我们没有classifier,我们只能够收集到一些资料,但没有这些资料的label
这是一个真实的Twitch Plays Pokemon例子,这个的例子是这样的:有人开了一个宝可梦的游戏,全世界的人都可以连接一起玩这个宝可梦的游戏。右边的框是每一个人都在输入指令同时操控这个游戏,这个游戏最多纪录好像是有八万人同时玩这个游戏。当大家都在同时操作同一个角色时,玩起来其实是相当崩溃的。
人们玩的时候就非常的崩溃,那么崩溃的原因是什么呢?可能是因为有网络小白(Troll)。有一些人根本就不会玩,所以大家都没有办法继续玩下去;或者觉得很有趣;或者是不知名的恶意,不想让大家结束这个游戏。人们相信有一些小白潜藏在人们当中,他们想要阻挠游戏的进行。
所以我们就可以用异常侦测的技术,假设多数的玩家都是想要破关的(训练资料),我们可以从多数玩家的行为知道正常玩家的行为是咋样的,然后侦测出异常的玩家(网络小白)。至于侦测出来给网路小白做什么,还需要待讨论的问题。有人说:小白只是人们的幻想,为什么这么说呢?
也许实际上根本就没有在阻挠这个游戏的进行,只是因为大家同时玩这个游戏时,大家的想法会是不一样的,这样玩起来会非常的卡。甚至有人说若没有网络小白,大家也根本没办法玩下去,因为在这个游戏里面同时可能会有非常多的指令被输入,而系统pick一个指令,所以多数时你的指定根本就没有被选到。如果所有人的想法都是一致的(输入同一个指令),结果某一个人的指令被选到。那你可能就会觉得这有什么好玩的,反正我又没有操控那个角色。所以大家相信有网络小白的存在,大家一起联手起来抵挡网络小白的攻击,这会让你觉得最后系统没有选到我,但是至少降低了小白被选到的可能,所以大家可以继续玩下去。
我们需要一些训练的资料,每一个x代表一个玩家,如果我们使用machine learning的方法来求解这个问题,首先这个玩家能够表示为feature vector。向量的第一维可以是玩家说垃圾话的频率,第二维是统计玩家无政府状态发言。

我们刚才可以根据分类器的conference来判断是不是异常的资料,但我们现在只有大量的训练资料,没有label。我们在没有classifier的情况下可以建立一个模型,这个模型是告诉我们P(x)的机率有多大。(根据这些训练资料,我们可以找出一个机率模型,这个模型可以告诉我们某一种行为发生的概率多大)。如果有一个玩家的机率大于某一个阀值(threshold),我们就说他是正常的;如果机率小于某一个阀值(threshold),我们就说他是异常的。
如图这是一个真实的资料,假设每一个玩家可以用二维的向量来描述(一个是说垃圾话的机率,一个是无政府状态发言的机率)。

如果我们只看说垃圾话的那一维如图所示,会发现并不是完全不说垃圾话的是最多的。很多人可能会想象说大多数人是在民主状态下发言的(民主时比较想发言,无政府混乱时不想发言),但是实际上统计的结果跟直觉的想象是不一样的,如图所示大多数人有八成的机率是在无政府状态下发言的,因为这个游戏多数时间是在无政府状态下进行的。游戏进行到某一个地方以后,官方决定加入民主机制(20秒内最多人选择的那一个行为是控制角色所采取的决策,这个听起来好像是很棒的主意,马上就遭到了大量的反对。在游戏里面要投票选择民主状态还是无政府状态,若很多人选择无政府状态,就会进入无政府状态。
事实上很多人强烈支持无政府状态,强烈反对民主状态,所以这个游戏多数是在无政府状态下进行。假设一个玩家不考虑自己是要在什么状态下发言,大多数人有八成的机率是在无政府下进行发言,有人甚至觉得多数小白是在民主状态下发言,因为进入了民主状态,所以他要多发言才能够让他的行为被选中,所以小白会特别喜欢在民主状态下发言。
我们还没有讲任何的机率模型,从这个图上可以很直觉的看出一个玩家落在说垃圾的话机率低,通常在无政府状态下发言,这个玩家有可能是一个正常的玩家。假设有玩家落在有五成左右的机率说垃圾话,二成的机率在无政府状态下发言;或者落在有七成左右的机率说垃圾话,七成的机率在无政府状态下发言,显然这个玩家比较有可能是一个不正常的玩家。我们直觉上明白这件事情,但是我们仍然希望用一个数值化的方法告诉我们玩家落在哪里会更加的异常。
我们需要likelihood这个概念:我们收集到n笔资料,假设我们有一个probability density function,其中是这个probability density function的参数(的数值决定这个probability density function的形状),必须要从训练资料中学习出来。假设这个probability density function生成了我们所看到的数据,而我们所做的事情就是找出这个probability density function究竟长什么样子。

likelihood的意思是:根据probability density function产生如图所示的数据机率有多大。若严格说的话,并不是机率,它的output是probability density;输出的范围也并不是(0,1),有可能大于1。
根据probability density function产生的机率,乘以根据probability density function产生的机率,一直乘到根据probability density function产生的机率,得到的结果就是likelihood。likelihood的可能性显然是由控制的,选择不同的就有不同的probability density function,就可以算出不同的likelihood。
而我们现在并不知道这个是多少,所以我们找一个,使得算出来的likelihood是最大的。

第二项分母为 Determinant 行列式
一个常用的probability density function就是Gaussian Distribution,你可以将这个公式想象为一个function,这个function就是输入一个vector x,输出为这个vector x被sample到的机率。这个function由两个参数(和covariance matrix )所控制,它们相当于我们刚才所讲的。这个Gaussian function的形状由和covariance matrix 所控制。将替换为,不同的就有不同的probability density function。
假设如图所示的数据是由左上角的来生成的,它的likelihood是比较大(Gaussian function的特性就是在附近时data被sample的机率很高)假设这个远离高密度,若从这个被sample出来的资料应该落在这个蓝色圈圈的范围内,但是资料没有落在这个蓝色圈圈的范围内,显然这样计算出来的likelihood是比较低的。
所以我们要做的事情就是穷举所有的,观察哪个计算的likelihood最大,那这个就是我们要找的。得到以后就可以知道产生这笔资料的Distribution的形状。
但是往往有同学问的问题是:为什么要用Gaussian Distribution,为什么不用其它的Distribution。最简答的答案是:我选别的Distribution,你也会问同样的问题。Gaussian是真的常用,这是一个非常非常强的假设,因为你的资料分布可能根本就不是Gaussian,有可能你会做的的更好,但不是我们这门课要讲的范围。
如果是一个非常复杂的function(network),而操控这个network的参数有非常大量,那么就不会有那么强的假设了,就会有多的自由去选择function来产生资料。这样就不会限制在看起来就不像Gaussian产生的资料却硬要说是Gaussian产生的资料。因为我们这门课还没有讲到其它进阶的生成模型,所以现在用Gaussian Distribution来当做我们资料是由Gaussian Distribution所产生的。
可以代入相应的公式来解这个这个公式,等于将所有的training data x做平均,结果为,等于将x减去乘以x减去的转置,然后做平均,得到的结果为

我们根据如图所示的资料找出了和,接下来就可以做异常侦测了。将代入probability density function,若大于某一个阀值(threshold)就说明是正常的,若小于某一个阀值(threshold)就说明是异常的。
每一笔资料都可以代入probability density function算出一个数值,结果如图所示。若落在颜色深的红色区域,就说明算出来的数值越大,越是一般的玩家,颜色浅的蓝色区域,就说明这个玩家的行为越异常。其中就是如图所示的等高线的其中一条,若有一个玩家落在很喜欢说垃圾话,多数喜欢在无政府状态下发言的区域,就说明是一个正常的玩家。若有一个玩家落在很少说垃圾话,特别喜欢在民主时发言,就说明是一个异常的玩家。
machine learning最厉害的就是让machine做,所以你要选择多少feature都可以,把能想到觉得跟判断玩家是正常的还是异常的feature加进去。

有了这些feature以后就训练训练出,然后创建一个新的玩家代入这个function,就可以知道这个玩家算出来的分数有多高(对这个function进行log变化,因为一般function计算出来的分数会比较小)。
假设输入的这个玩家有0.1 percent说垃圾话,0,9 percent无政府状态下发言,0.1 percent按START键,1.0 percent跟大家一样,0.0 percent唱反调,这个玩家计算出来的likelihood为-16。
假设输入的这个玩家有0.1 percent说垃圾话,0,9 percent无政府状态下发言,0.1 percent按START键,0.0 percent跟大家一样,0.3 percent唱反调,这个玩家计算出来的likelihood为-22。
假设输入的这个玩家有0.1 percent说垃圾话,0,9 percent无政府状态下发言,0.1 percent按START键,0.7 percent跟大家一样,0.0 percent唱反调,这个玩家计算出来的likelihood为-2。
我们可以看到第一个和第三个玩家除了第四个特征都一样,但是第一个玩家和大家的选择完全一样,第三个玩家和大家的选择在大多数情况下是相同的,这时第一个得到的分数反而低,是因为机器会觉得如果你和所有人完全一样这件事就是很异常的。
上述是用生成模型(Generative Model) 来进行异常侦测这件事情,我们也可以使用Auto-encoder来做这件事情。
我们把所有的训练资料训练一个Encoder,Encoder所做的事情是将输入的图片(辛普森)变为code(一个向量),Decoder所做事情是将code解回原来的图片。训练时Encoder和Decoder是同时训练,训练目标是希望输入和输出越接近越好。
测试时将一个图片输入Encoder,Decoder还原原来的图片。如果这张图片是一个正常的照片,很容易被还原为正常的图片。因为Auto-encoder训练时输入的都是辛普森家庭的图片,那么就特别擅长还原辛普森家庭的图片。
但是若你输入异常的图片,通过Encoder变为code,再通过Decoder将coede解回原来的图片时,你会发现无法解回原来的图片。解回来的图片跟输入的图片差很多时,这时你就可以认为这是一张异常的图片。

machine learning中也有其它做异常侦测的方法,比如One-class SVM,只需要正常的资料就可以训练SVM,然后就可以区分正常的还是异常的资料。
Isolated Forest,它所做的事情跟One-class SVM所做的事情很像(给出正常的训练进行训练,模型会告诉你异常的资料是什么模样)。

Typical GAN要做的事情是找到一个Generator,Generator就是一个function。这个function的输入是random vector,输出是我们要这个Generator生成的图片。
举例来说:假设要机器做一个动画的Generator,那么就要收集很多动画人物的头像,然后将这些动画人物的头像输入至Generator去训练,Generator 就会学会生成二次元人脸的图像。
那怎么训练这个Generator 呢,模型的架构是什么样子的呢?
最基本的GAN就是对Generator输入vector,输出就是我们要它生成的东西。我们以二次元人物为例,假设我们要机器画二次元人物,那么输出就是一张图片(高维度的向量)。Generator就像吃一个低维度的向量,然后输出一个高维度的向量。
GAN有趣的地方是:我们不只训练了Generator,同时在训练的过程中还会需要一个Discriminator。Discriminator的输入是一张图片,输出是一个分数。这个分数代表的含义是:这张输入的图片像不像我们要Generative产生的二次元人物的图像,如果像就给高分,如果不像就给低分。
接下来要讲的是Generator和Discriminator是咋样训练出来的,Generator和Discriminator都是neuron network,而它们的架构是什么样的,这取决于想要做的任务。举例来说:你要generator产生一张图片,那显然generator里面有很多的deconvolution layer。若要generator产生一篇文章或者句子,显然要使用RNN。
我们今天不讲generator跟discriminator的架构,这应该是取决于你想要做什么样的事情。
generator跟discriminator是某种network,训练neuron network时要随机初始化generator和discriminator的参数。
在初始化参数以后,在每一个training iteration要做两件事
step1:固定generator,然后只训练discriminator(看到好的图片给高分,看到不好的图片给低分)。从一个资料库(都是二次元的图片)随机取样一些图片输入 discriminator,对于discriminator来说这些都是好的图片。因为generator的参数都是随机给定的,所以给generator一些向量,输出一些根本不像二次元的图像,这些对于discriminator来说就是不好的图片。接下来就可以教discriminator若看到上面的图片就输出1,看到下面的图片就输出0。训练discriminatro的方式跟我们一般训练neuron network的方式是一样的。

有人会把discriminator当做回归问题来做,看到上面的图片输出1,看到下面的图片就输出0也可以。有人把discriminator当做分类的问题来做,把上面好的图片当做一类,把下面不好的图片当做另一类也可以。训练discriminator没有什么特别之处,跟我们训练neuron network或者binary classifier是一样的。唯一不同之处就是:假设我们用训练binary classifier的方式来训练discriminator时,不一样的就是binary classifier其中class的资料不是人为标注好的,而是机器自己生成。
step2:固定住discriminator,只更新generator。
一般我们训练network是minimize 人为定义的loss function,在训练generator时,generator学习的对象不是人定的loss function/objective function,而是discriminator。你可以认为discriminator就是定义了某一种loss function,等于机器自己学习的loss function。
generator学习的目标就是为了骗过discriminator,我们让generator产生一些图片,在将这些图片输入进discriminator,然后discrimination就会给出这些图片一些分数。
接下来我们把generator和discriminator串在一起视为一个巨大的network。这个巨大的network输入是一个向量,输出是一个分数,在这个network中间hidden layer的输出可以看做是一张图片。
我们训练的目标是让输出越大越好,训练时依然会做backpropagation,只是要固定住discriminator,只是调整generator。调整完generator后输出会发生改变,generator新的输出会让discriminator给出高的分数。

实际上在训练时,训练discriminator一次,然后训练一次generator(固定discriminator),接下来由新的generator产生更多需要被标为0的图片,再去调discriminator,再调generator......generator和discriminator交替训练,就做二次元人物的生成。网络上最好的二次元人物生成的结果。

众所周知,GAN这个技术是比较难train起来的,所以有很多人提出了更好的训练GAN的方法,WGAN,improve WGAN…
刚才是让机器随机的产生一些东西,这些不见得是我们想要的。我们更多的想要控制机器产生出来的东西。
我们可以训练一个Generator,这个generator的输入是一段文字,输出是这段文字对应的图像。举例来说:我们现在输入“Girl with red hair”,它就输出一个。根据某一个输入产生对应输出的generator被叫做Conditional GAN。
现在用文字产生影像作为示例,如何可以训练一个network根据文字来产生图像,最直觉的方法就是使用supervised learning。假设可以收集到文字跟影像之间的对应关系(这些图片有人标识每张图片对应的文字是什么),接下来就可以完全的套用传统的supervised learning的方法。直接训练一个network,它的输入是一段文字,输出是一张图像,希望这个输出跟原始的图像越接近越好。可以用这种方法直接训练,看到文字产生图像。
过去用这种方法(看到文字产生图像)来训练,训练出来的结果并不太好。为什么呢?举例说明:假设要机器学会画火车,但是训练资料里面有很多不同形态的火车,当network输入火车时它的正确答案有好多个,对于network来说会产生它们的平均作为输出。如果用supervised learning的方法产生出来的图像往往是非常模糊。
所以我们需要有新的技术(Conditional GAN)来做根据文字产生图像,对于Conditional GAN,我们也需要文字与图像的对应关系(supervised learning),但是它跟一般的supervised learning的训练目标是不一样的。事实上Conditional GAN也可以在unsupervised learning的情况下进行训练,后面的内容会涉及到。
Conditional GAN是跟着discriminator来进行学习的,要注意的是:在做Conditional GAN时跟一般的GAN是不一样的。
在第一部分讲一般的GAN时,discriminator是输入一张图片,然后判断它好还是不好。现在在Conditional CAN的情况下,discriminator只输入一张图片会遇到的问题是:对于discriminator想要骗过generator太容易了,它只要永远产生好的图像就行了。举例来说:永远产生一只很可爱的猫就可以骗过discriminator(对于discriminator来说那只猫是好的图片),然后就结束了。Generator就会学到不管现在输入什么样的文字,就一律忽视,都产生猫就好了,这显然不是我们想要的。

在进行Conditional GAN时往往有两个输入,discriminator应该同时看generator的输入(文字)和输出(图像),然后输出一个分数,这个分数同时代表两个含义。第一个含义是两个输入有多匹配,第二个含义是输入图像有多好。
训练discriminator时要给它一些好的输入,这些是要给高分的。可以从datasets里面sample出文字与图像,告诉discriminator看到这些文字和图像应该给出高分。
对于另外一个case而言,什么情况会给出低分呢?
按照我们在第一部分讲一般GAN的想法,我们可能就是把文字输入generator,让他产生一些图片,这些文字和generator产生出来的图像要给予低分。
光是这么做discriminator会学到判断现在的输入是好还是不好,不管文字的部分只管图像的部分,这显然不是我们想要的。
所以在做Conditional GAN时,要给低分的case是要有两种。一个是跟一般的GAN一样是用generator生成图片;另外一个是从资料库里面sample出一些好的图片,但是给这些好的图片一些错误的文字。这时discriminator就会学到:并不是所有好的图片都是对的,如果好的图片对应都错误的文字它也是不好的。这样discriminator就会学懂文字与图像之间应该要有什么样的关系。

其实上述使用Conditional GAN 根据文字生成影像的应用已经满坑满谷了,其实只要你有pair data 你都可以尝试使用Conditional GAN,这里实作了一个例子,训练了一个Generator,输入声音,可以输出对应的画面。
训练Conditional GAN必须要有pair data,影像跟声音的对应关系其实并不难收集,我们可以收集到很多的video,将video中的audio部分拿出来就是声音,将image frame部分拿出来就是image,这样就有了pair data,就可以训练network。举例来说:听到狗叫声,就画一只狗出来。
当听到第一行第一列声音时,机器觉得它是一条小溪;听到第二行第一列的声音时,机器觉得它是在海上奔驰的快艇;我现在担心机器是不是背了一些资料库里面的图片,并没有学会声音跟影像之间的关系,所以我们把声音调大,然后就产生了一条越来越大的瀑布。我们把快艇的声音调大,产生的就是快艇在海上快速的奔驰,水花就越来越多。机器有时候产生的结果也会非常的差。
我们刚才尝试了用文字产生影像,现在反过来想,用影像来产生文字。我们将影像用在Multi-label image Classifier上,给机器看一张图片,让机器告诉我们图片有哪些物件,比如有球,球棒等等,正确答案不只有一个。我们在课堂里讲的分类问题,每一个输入都只属于每一个类别。但是在Multi-label image classifier的情况下,同一张图片可以同时属于不同的类别。
一张图片可以同时属于不同类别这件事,我们可以想成是一个生成的问题,现在Multi-label image Classifier是一个Conditional Generator,它的输入是一张图片(图片是condition),label是Generator输出。接下来就当做Conditional GAN进行训练。

这些是一些实验的结果,其中使用F1 score来当做评价指标(分数越高代表分类越正确)。我们试了不同的architecture(从VGG-16到Resent-152),假设现在不是用一般的训练法(nn输出和ground truth越接近越好),而是用Conditional GAN的方法时,你会发现在不同的network架构下,结果都是比较好的。为什么加上GAN的方法会比较好呢?因为加上GAN以后会考虑label和label之间的dependence。
根据一张图片跟人脸landmarks去产生另外一张人脸,也就是说你现在可以做:给它一张蒙娜丽莎的脸,然后在画一些人脸的landmarks,这样你就可以让蒙娜丽莎开始讲话。
https://arxiv.org/abs/1905.08233
刚才在讲Conditional GAN时我们需要输入和输出之间的对应关系,但是事实上有机会在不知道输入和输出之间的对应关系的情况下,可以教机器咋样将输入的内容转化为输出。这个技术最常见到的应用是风格转化。
Cycle GAN想要做的事情是:训练一个generator,输入doamin X(真实的画作),输出是梵高的画作。除了训练一个generator还需要训练一个discriminator,discriminator做的事情是:看很多梵高的画作,看到梵高的画作就给高分,看到不是梵高的画作就给低分。
generator为了要骗过discriminator,那我们期待产生出来的照片像是梵高的画作,光是这样做是不够的,因为generator会很快发现discriminator看的就是它的输出,那么generator就直接产生梵高的画作,完全无视输入的画作,只要骗过discriminator整个训练就结束了。
为了解决这个这也问题我们还需要再加上一个generator,这个generator要做的事情是根据第一个generator的输出还原原来的输入(输入一张Domain X,第一个generator将其转化为Domain Y的图,第二个generator在将其还原为Domain X,两者越接近越好)

现在加上了这个限制,第一个generator就不能够尽情的骗过discriminator,不能够直接产生梵高的自画像。如果直接转换为梵高的自画像,那么第二个generator就无法将梵高的自画像还原。所以第一个generator想办法将Domain ,但是原来图片最重要的资讯仍然被保留了下来,那么第二个generator才会有办法将其还原。输出跟输入越接近越好,这件事叫做Cycle consistency。
Cycle GAN其实是可以双向的,我们刚才讲的是先将Domain X转换为Domain Y,再将Domain Y转换为Domain X。现在我们可以将Domain Y转换为Domain X,然后再用一个蓝色的generator将Domain X转换为Domain Y,让输出和输入越接近越好。

同样的技术不只是用在影像上,可以应用在其它领域上。举例来说:假设Domain X和Domain Y分别是不同人讲的话(语音),那就可以做语音的风格转换。假设Domain X和Domain Y是两种不同的风格文字,那就可以做文字的风格转化。假设我们把Domain X替换成负面的句子,将Domain Y换成正面的句子,我们就可以训练一个generator,可以将负面的句子转换为正面的句子。
如果直接将影像的技术套用到文字上是会有些问题,如果generator在做文字风格转换的时候,输入是一个句子,输出也是一个句子。如果输入和输出分别是句子的话,这时应该使用Seq2seq model作为网络架构。在训练时仍然很期待使用Backpropagation将Seq2seq和discriminator串在一起,然后使用backpropagation固定discriminator,只训练generator,希望输出的分数越接近越好。
但在文字上没有办法直接使用bachpropagation,因为Seq2seq model输出的是离散的seq,是一串token。原来我们将generator的输看做是一个巨大network的hidden layer,那是因为在影像上generator的输出是连续的,但是在文字上generator的输出是离散的(不能微分)。
如何解决呢,在文献上有各式各样的解决办法。
Three Categories of Solutions
Gumbel-softmax:[Matt J. Kusner, et al, arXiv, 2016]
Continuous Input for Discriminator:[Sai Rajeswar, et al., arXiv, 2017][Ofir Press, et al., ICML workshop, 2017][Zhen Xu, et al., EMNLP, 2017][Alex Lamb, et al., NIPS, 2016][Yizhe Zhang, et al., ICML, 2017]
Reinforcement Learning:[Yu, et al., AAAI, 2017][Li, et al., EMNLP, 2017][Tong Che, et al, arXiv, 2017][Jiaxian Guo, et al., AAAI, 2018][Kevin Lin, et al, NIPS, 2017][William Fedus, et al., ICLR, 2018]
Unsupervised Conditional GAN其实除了风格转换以外还可以做其它的事情,比如说:Unsupervised 语音辨识。我们在做语音辨识时通常是supervised,也就是说我们要给机器一大堆的句子,还要给除句子对应的文字是什么,这样的句子收集上万小时,然后期待机器自动学会语音辨识。但是世界上语言有7000多种,其实不太可能为每一种语言都收集训练资料。
所以能不能想象语音辨识能不能是Unsupervised的,也就是说我们收集一大堆语言,一大堆文字,但是我们没有收集语言跟文字之间的对应关系。机器做的就是听一大堆人讲话,然后上面读一大堆文章,然后期待机器自动学会语音辨识。
现在有很多人很笼统的问一个问题是:语音辨识可以做到什么样的错误率、正确率,这个问题我都是没有办法去回答的,这个问题就好像是你的数学会考多少分,都没有说是考哪一门数学。所以你今天要问一个语言辨识系统的正确率有多少,你应该问是拿什么样的资料去测试它。
这张图讲的是supervised learning过去变化的情形(纵轴是正确率,横纵是时间),Unsupervised learning(没有提供给机器文字与语音之间的对应关系)可以做到跟三十年前supervised learning的结果一样好。


Component-by-component (Auto-regressive Model)
Variational Auto-encoder
Generative Adversarial Network
A generator G is a network. The network defines a probability distribution

Flow-based model directly optimizes the objective function.
Demo
The determinant of a square matrix is a scalar that provides information about the matrix.

高维空间中的体积的概念


如上图所示,给定两组数据和,其中z服从已知的简单先验分布(通常是高斯分布),服从复杂的分布(即训练数据代表的分布),现在我们想要找到一个变换函数,它能建立一种z到x的映射,使得每对于中的一个采样点,都能在中有一个(新)样本点与之对应。
如果这个变换函数能找到的话,那么我们就实现了一个生成模型的构造。因为,中的每一个样本点都代表一张具体的图片,如果我们希望机器画出新图片的话,只需要从中随机采样一个点,然后通过映射,得到新样本点,也就是对应的生成的具体图片。
接下来的关键在于,这个变换函数f如何找呢?我们先来看一个最简单的例子。

如上图所示,假设z和x都是一维分布,其中z满足简单的均匀分布:,x也满足简单均匀分布:。
那么构建z与x之间的变换关系只需要构造一个线性函数即可:。
下面再考虑非均匀分布的更复杂的情况

如上图所示,与都是较为复杂的分布,为了实现二者的转化,我们可以考虑在很短的间隔上将二者视为简单均匀分布,然后应用前边方法计算小段上的,最后将每个小段变换累加起来(每个小段实际对应一个采样样本)就得到最终的完整变换式。
如上图所示,假设在上近似服从均匀分布,在上也近似服从均匀分布,于是有(因为变换前后的面积/即采样概率是一致的),当与极小时,有:
又考虑到有可能是负值,而都为非负,所以的实际关系需要加上绝对值
进一步地做推广,我们考虑z与x都是二维分布的情形。

如上图所示,z与x都是二维分布,左图中浅蓝色区域表示初始点在方向上移动,在方向上移动所形成的区域,这一区域通过映射,形成x域上的浅绿色菱形区域。其中,二维分布与均服从简单均匀分布,其高度在图中未画出(垂直纸面向外)。代表改变时,改变量;是改变时,改变量。代表改变时,改变量;是改变时,改变量.
因为蓝色区域与绿色区域具有相同的体积,所以有:
其中代表行列式计算,它的计算结果等于上图中浅绿色区域的面积(行列式的定义)。下面我们将移至左侧,得到:
即可得到
当变化很小时
做转置,转置不会改变行列式
就得到
根据雅各比行列式的逆运算,得到
至此,我们得到了一个比较重要的结论:如果与分别满足两种分布,并且通过函数能够转变为,那么与中的任意一组对应采样点与之间的关系为:
那么基于这一结论,再带回到生成模型要解决的问题当中,我们就得到了Flow-based Model(流模型)的初步建模思维。

上图所示,为了实现 到 间的转化,待求解的生成器G的表达式为:
基于前面推导, 我们有 中的样本点与 中的样本点间的关系为:
其中
所以,如果的目标式能够通过上述关系式求解出来,那么我们就实现了一个完整的生成模型的求解。
Flow-based Model就是基于这一思维进行理论推导和模型构建,下面详细解释Flow-based Model的求解过程。
将上述式子取log,得到
现在,如果想直接maximize求解这个式子有两方面的困难。
第一个困难是是不好计算的——由于的Jacobian矩阵一般维度不低(譬如256*256矩阵),其行列式的计算量是异常巨大的,所以在实际计算中,我们必须对的Jacobian行列式做一定优化,使其能够在计算上变得简洁高效。
第二个困难是,表达式中出现了,这意味着我们要知道长什么样子,而我们的目标是求,所以这需要巧妙地设计的结构使得也是好计算的,同时要求z和x的dimension是一样的才能使存在。
这些要求使得G有很多限制。由于单个G受到了较多的约束,所以可能表征能力有限,因此可以进行多层扩展,其对应的关系式只要进行递推便可。

下面我们来逐步设计G的结构,首先从最基本的架构开始构思。考虑到必须是存在的且能被算出,这意味着G的输入和输出的维度必须是一致的并且G的行列式不能为0。
然后,既然可以计算出来,而的目标表达式只与有关,所以在实际训练中我们可以训对应的网络,然后想办法算出G来,并且在测试时改用G做图像生成。

如上图所示,在训练时我们从真实分布中采样出,然后去训练,使得通过生成的满足特定的先验分布,maximize上面的objective function,这里一般需要保证 和 具有相同的尺寸;接下来在测试时,我们从z中采样出一个点,然后通过G生成的样本就是新的生成图像。
由于是符合Normal Distribution,等于0时最大,因此第一项让趋向于0,第二项又让远离0。
接下来开始具体考虑 G 的内部设计,为了让可以计算并且 G 的 Jacobian 行列式也易于计算,Flow-based Model采用了一种称为耦合层(Coupling Layer)的设计来实现。其被应用在NICE和Real NVP这两篇论文当中。
整个流程可以表述为
先将输入 拆分成两个部分(可以是按channel进行拆分,也可以还是按照pixel的location进行拆分), 对于上面的部分 直接copy得到对应的output ,而对于下面的分支则有如下的变换(公式中符号代表element-wise相乘)
可以简化为: 或 。
之所以采用以上设计结构的原因在于上述的结构容易进行逆运算。

都被分成两部分, 前 维直接copy,因此求逆也是直接copy。
后维使用两个函数进行仿射变化,可以将 之间看作线性关系,因此求逆时直接进行反操作即可。
可以是任意复杂的函数,我们并不需要求他的逆。在逆向过程中,容易得到 和 。

解决完 部分,还需要求解生成器对应的雅可比矩阵 的行列式

我们们可以将生成器对应的雅克比矩阵分为以上的四个子块, 左上角由于是直接copy的,所以对应的部分应该是一个单位矩阵,右上角中由于 与 没有任何关系,所以是一个零矩阵,而左下角We don't care,因为行列式的右上角为0,所以只需要求解主对角线上的值即可。
右下角由于,是一对一的关系,因此是对角阵,对角线上的元素分别为 。
所以上述的 。
那么这么一来coupling layer的设计把 和 这个问题都解决了
我们将多个耦合层堆叠在一起,从而形成一个更完整的生成器。但是这样会有一个新问题,就是最终生成数据的前 d 维与初始数据的前d 维是一致的,这会导致生成数据中总有一片区域看起来像是固定的图样(实际上它代表着来自初始高斯噪音的一个部分),我们可以通过将复制模块(copy)与仿射模块(affine)交换顺序的方式去解决这一问题。

如上图所示,通过将某些耦合层的copy与affine模块进行位置上的互换,使得每一部分数据都能走向 copy->affine->copy->affine 的交替变换通道,这样最终的生成图像就不会包含完全copy自初始图像的部分。值得说明的是,在图像生成当中,这种copy与affine模块互换的方式有很多种,下面举两个例子来说明:

上图展示了两种按照不同的数据划分方式做 copy 与 affine 的交替变换。左图代表的是在像素维度上做划分,即将横纵坐标之和为偶数的划分为一类,和为奇数的划分为另外一类, 然后两类分别交替做 copy 和 affine 变换(两两交替);右图代表的是在通道维度上做划分, 通常图像会有三通道,那么在每一次耦合变换中按顺序选择一个通道做 copy,其他通道做 affine(三个轮换交替),从而最终变换出我们需要的生成图形出来。
更进一步地,如何进行 copy 和 affine 的变换能够让生成模型学习地更好,这是一个可以由机器来学习的部分,所以我们引入 W 矩阵,帮我们决定按什么样的顺序做 copy 和 affine 变换,这种方法叫做 1×1 convolution(被用于知名的GLOW当中)。

can shuffle the channels. 所以copy时可以只copy第一个channel,反正1×1 convolution会在适当的时机对channel进行对调。
1×1 convolution 只需要让机器决定在每次仿射计算前对图片哪些区域实行像素对调,而保持 copy 和 affine 模块 的顺序不变,这实际上和对调 copy 和 affine 模块顺序产生的效果是一致的。
比如右侧三个通道分别是1,2,3,经过一个矩阵就会变成3,1,2,相当于对通道调换了顺序。而coupling layer不要动,只copy某几个channel。至于channel如何交换,需要机器学出来。
也在里面,也需要invertible。

下面我们看一下,将引入flow模型之后,对于原始的Jacobian行列式的计算是否会有影响。
对于每一个3*3维划分上的仿射操作来说,由,可以得到Jacobian行列式的计算结果就是
代入到整个含有d*d个3*3维的仿射变换矩阵当中,只有对应位置相同的时候才会有权值,得到最终的Jacobian行列式的计算结果就为

因此,引入1×1 convolution后的的Jacobian行列式计算依然非常简单,所以引入1×1 convolution是可取的,这也是GLOW这篇Paper最有突破和创意的地方。


Flow-based Model可以用于语音合成

综上,关于 Flow-based Model 的理论讲解和架构分析就全部结束了,它通过巧妙地构造仿射变换的方式实现不同分布间的拟合,并实现了可逆计算和简化雅各比行列式计算的功能和优点,最终我们可以通过堆叠多个这样的耦合层去拟合更复杂的分布变化,从而达到生成模型需要的效果。
迁移学习,主要介绍共享layer的方法以及属性降维对比的方法
迁移学习,transfer learning,旨在利用一些不直接相关的数据对完成目标任务做出贡献
以猫狗识别为例,解释“不直接相关”的含义:
input domain是类似的,但task是无关的
比如输入都是动物的图像,但这些data是属于另一组有关大象和老虎识别的task
input domain是不同的,但task是一样的
比如task同样是做猫狗识别,但输入的是卡通图

迁移学习问的问题是:我们能不能再有一些不相关data的情况下,然后帮助我们现在要做的task。
为什么要考虑迁移学习这样的task呢?
举例来说:在speech recognition里面(台语的语音辨识),台语的data是很少的(但是语音的data是很好收集的,中文,英文等)。那我们能不能用其他语音的data来做台语这件事情。
或者在image recongnition里面有一些是medical images,你想要让机器自动诊断说,有没有 tumor 之类的,这种medical image其实是很少的,但是image data是很不缺的。
或者是在文件的分析上,你现在要分析的文件是某个很 specific 的 domain,比如说你想要分析的是,某种特别的法律的文件,那这种法律的文件或许 data 很少,但是假设你可以从网络上 collect 一大堆的 data,那这些 data,有可能是有帮助的。
用不相干的data来做domain其他的data,来帮助现在的task,是有可能的。事实上,我们在日常生活中经常会使用迁移学习,比如我们会把漫画家的生活自动迁移类比到研究生的生活。
迁移学习有很多的方法,它是很多方法的集合。下面你有可能会看到我说的terminology可能跟其他的有点不一样,不同的文献用的词汇其实是不一样的,有些人说算是迁移学习,有些人说不算是迁移学习,所以这个地方比较混乱,你只需要知道那个方法是什么就好了。
我们现在有一个我们想要做的task,有一些跟这个task有关的数据叫做target data,有一些跟这个task无关的data,这个data叫做source data。这个target data有可能是有label的,也有可能是没有label的,这个source data有可能是有label的,也有可能是没有label的,所以现在我们就有四种可能,所以之后我们会分这四种来讨论。
这里target data和source data都是带有标签的:
target data:,作为有效数据,通常量是很少的
如果target data量非常少,则被称为one-shot learning
source data:,作为不直接相关数据,通常量是很多的

模型微调的基本思想:用source data去训练一个model,再用target data对model进行微调(fine tune)
所谓“微调”,类似于pre-training,就是把用source data训练出的model参数当做是参数的初始值,再用target data继续训练下去即可,但当target data非常少时,可能会遇到的challenge是,你在source data train出一个好的model,然后在target data上做train,可能就坏掉了。
所以训练的时候要小心,有许多技巧值得注意
如果现在有大量的source data,比如在语音识别中有大量不同人的声音数据,可以拿它去训练一个语音识别的神经网络,而现在你拥有的target data,即特定某个人的语音数据,可能只有十几条左右,如果直接拿这些数据去再训练,肯定得不到好的结果。

此时我们就需要在训练的时候加一些限制,让用target data训练前后的model不要相差太多:
注:这里的限制就类似于regularization
现在我们已经有一个用source data训练好的model,此时把该model的某几个layer拿出来复制到同样大小的新model里,接下来只用target data去训练余下的没有被复制到的layer
这样做的好处是target data只需要考虑model中非常少的参数,这样就可以避免过拟合。
如果target data足够多,fine-tune 整个model也是可以的。

Layer Transfer是个非常常见的技巧,接下来要面对的问题是,哪些layer应该被transfer,哪些layer不应该去transfer呢?
有趣的是在不同的task上面需要被transfer的layer往往是不一样的:
在语音识别中,往往迁移的是最后几层layer,再重新训练与输入端相邻的那几层
由于口腔结构不同,同样的发音方式得到的发音是不一样的,NN的前几层会从声音信号里提取出发音方式,再用后几层判断对应的词汇,从这个角度看,NN的后几层是跟特定的人没有关系的,因此可做迁移
在图像处理中,往往迁移的是前面几层layer,再重新训练后面的layer
CNN在前几层通常是做最简单的识别,比如识别是否有直线斜线、是否有简单的几何图形等,这些layer的功能是可以被迁移到其它task上通用的
case by case,运用之妙,存乎一心

这边是 image 在 layer transfer 上的实验,这个实验做在 ImageNet 上,把 ImageNet 的 corpus,一百二十万张 image 分成 source 跟 target。这个分法是按照 class 来分的,我们知道 ImageNet 的 image一个 typical 的 setup 是有一千个 class,把其中五百个 class 归为 source data,把另外五百个 class 归为 target data。
横轴是我们在做 transfer learning 的时候,copy 了几个 layer。copy 0 个 layer 就代表完全没有做 transfer learning。这是一个 baseline ,就直接在 target data 上面 train 下去。纵轴是 top-1 accuracy,所以是越高越好。没有做 transfer learning 是白色这个点

只有 copy 第一个 layer 的时候,performance 稍微有点进步,copy 前面两个 layer,performance 几乎是持平的,但是 copy 的 layer 太多,结果是会坏掉。
这个实验显示说在不同的 data 上面,train 出来的 neural network,前面几个 layer 是可以共享的,后面几个可能是没有办法共享的。如果 copy 完以后,还有 fine-tune 整个 model 的话,把第一个 layer,在 source domain 上 train 一个 model,然后把第一个 layer copy 过去以后,再用 target domain fine-tune 整个 model,包括前面 copy 过的 layer 的话,那得到 performance 是橙色这条线,在所有的 case 上面都是有进步的。
其实这个结果很 surprised,不要忘了,这可是 ImageNet 的 corpus,一般在做 transfer learning 的时候,都是假设 target domain 的 data 非常少,这边 target domain 可是有六十万张,这 target domain 的 data 是非常多的。但是就算在这个情况下,再多加了另外六十张 image 做 transfer learning,其实还是有帮助的。
这两条蓝色的线跟 transfer learning 没有关系,不过是这篇paper里面发现一个有趣的现象。他想要做一个对照组,在 target domain 上面 learn 一个 model,把前几个 layer copy 过来,再用一次 target domain 的 data train 剩下几个 layer。前面几个 layer 就 fix 住,只 train 后面几个 layer,直觉上这样做应该跟直接 train 整个 model 没有太大差别,先 train 好一个 model,fix 前面几个 layer,接下来只 train 后面几个 layer,结果有些时候是会坏掉的。他的理由是 training 的时候,前面的 layer 跟后面的 layer他们其实是要互相搭配,所以如果只 copy 前面的 layer,然后只 train 后面的 layer,后面的 layer 就没有办法跟前面的 layer 互相搭配,结果有点差。如果可以 fine-tune 整个 model 的话,performance 就跟没有 transfer learning 是一样的。这是另一个有趣的发现,作者自己对这件事情是很 surprised。
这是另外一个实验结果,红色这条线是前一页看到的红色的这条线。这边假设 source 跟 target 是比较没有关系的,把 ImageNet 的 corpus 分成 source data 跟 target data 的时候把自然界的东西,通通当作 source,target 通通是人造的东西,桌子、椅子等等。这样 transfer learning 会有什么样的影响?

如果 source 跟 target 的 data 是差很多的,在做 transfer learning 的时候,performance 会掉的比较多,前面几个 layer 影响还是比较小的,如果只 copy 前面几个 layer,仍然跟没有 copy 是持平的,这意味着,就算是 source domain 跟 target domain 是非常不一样的,一边是自然的东西,一边是人造的东西,在 neural network 第一个 layer,他们仍然做的事情很有可能是一样的。黄色的这条线,烂掉的这条线是假设前面几个 layer 的参数是 random 的。
fine-tune仅考虑在target data上的表现,而多任务学习,则是同时考虑model在source data和target data上的表现
如果两个task的输入特征类似,则可以用同一个神经网络的前几层layer做相同的工作,到后几层再分方向到不同的task上,这样做的好处是前几层得到的data比较多,可以被训练得更充分。这样做的前提是:这两个task有共通性,可以共用前面几个layer。
有时候task A和task B的输入输出都不相同,两个不同task的input都用不同的neural network把它transform到同一个domain上去,中间可能有某几个 layer 是 share 的,也可以达到类似的效果

以上方法要求不同的task之间要有一定的共性,这样才有共用一部分layer的可能性
多任务学习一个很成功的例子就是多语言的语音辨识,假设你现在手上有一大堆不同语言的data(法文,中文,英文等),那你在train你的model的时候,同时可以辨识这五种不同的语言。这个model前面几个layer他们会共用参数,后面几个layer每一个语言可能会有自己的参数,这样做是合理的。虽然是不同的语言,但是都是人类所说的,所以前面几个layer它们可能是share同样的咨询,共用同样的参数。

在translation上,你也可以做同样的事情,假设你今天要做中翻英,也要做中翻日,你也把这两个model一起train。在一起train的时候无论是中翻英还是中翻日,你都要把中文的data先做process,那一部分neural network就可以是两种不同语言的data共同使用。
在过去收集了十几种语言,把它们两两之间互相做transfer,做了一个很大的 N x N 的 table,每一个 case 都有进步。所以目前发现大部分case,不同人类的语言就算你觉得它们不是非常像,但是它们之间都是可以transfer的。

上图为从欧洲语言去transfer中文,横轴是中文的data,纵轴是character error rate。假设你一开始用中文train一个model,data很少,error rate很大,随着data越来越多,error rate就可以压到30以下。但是今天如果你有一大堆的欧洲语言,你把这些欧洲语言跟中文一起去做multi-task training,用这个欧洲语言的data来帮助中文model前面几层让它train的更好。你会发现:在中文data很少的情况下,你有做迁移学习,你就可以得到比较好的性能。随着中文data越多的时候,中文本身performance越好,就算是中文有一百小时的 data,借用一些从欧洲语言来的 knowledge,对这个辨识也是有微幅帮助的。
所以这边的好处是:假设你做多任务学习的时候,你会发现你有100多个小时跟50小时对比,如果你有做迁移学习的话,你只需要1/2的data就可以跟有两倍的data做的一样好。
常常有人会担心说:迁移学习会不会有负面的效应,这是会有可能的,如果两个task不像的话,你的transfer 就是negative的。但是有人说:总是思考两个task到底之间能不能transfer,这样很浪费时间。所以有人 propose 了 progressive neural networks
如果两个task完全不相关,硬是把它们拿来一起训练反而会起到负面效果
而在Progressive Neural Network中,每个task对应model的hidden layer的输出都会被接到后续model的hidden layer的输入上,这样做的好处是:

这里target data不带标签,而source data带标签:
举例来说:我们可以说:source data是MNIST image,target data是MNIST-M image(MNIST image加上一些奇怪的背景)。MNIST是有label的,MNIST-M是没有label的,在这种情况下我们通常是把source data就视作training data,target data视作testing data。产生的问题是:training data跟testing data是非常mismatch的。

这个时候一般会把source data当做训练集,而target data当做测试集,如果不管训练集和测试集之间的差异,直接训练一个普通的model,得到的结果准确率会相当低。
实际上,神经网络的前几层可以被看作是在抽取feature,后几层则是在做classification,如果把用MNIST训练好的model所提取出的feature做t-SNSE降维后的可视化,可以发现MNIST的数据特征明显分为紫色的十团,分别代表10个数字,而作为测试集的数据却是挤成一团的红色点,因此它们的特征提取方式根本不匹配。

所以该怎么办呢?希望做的事情是:前面的feature extract 它可以把domain的特性去除掉,这一招较做Domain-adversarial training。也就是feature extract output不应该是红色跟蓝色的点分成两群,而是不同的domain应该混在一起。

那如何learn这样的feature extract呢?这边的做法是在后面接一下domain classifier。把feature extract output丢给domain classifier,domain classifier它是一个classification task,它要做的事情就是:根据feature extract给它的feature,判断这个feature来自于哪个domain,在这个task里面,要分辨这些feature是来自MNIST还是来自与MNIST-M。
有一个generator 的output,然后又有discriminator,让它的架构非常像GAN。但是跟GAN不一样的事情是:之前在GAN那个task里面,你的generator要做的事情是产生一个image,然后骗过discriminator,这件事很难。
但是在这个Domain-adversarial training里面,要骗过domain classifier太简单了。有一个solution是:不管看到什么东西,output都是0,这样就骗过了classifier。

所以你要在feature extract增加它任务的难度,所以feature extract它output feature不仅要骗过domain classifier还要同时让label predictor做好。这个label predictor它就吃feature extract output,然后它的output就是10个class。
所以今天你的feature extract 不只要骗过domain classifier,还要满足label predictor的需求。抽出的feature不仅要把domain的特性消掉,同时还要保留原来feature的特性。
那我们把这三个neural放在一起的话。实际上就是一个大型的neural network,是一个各怀鬼胎的neural network(一般的neural network整个参数想要做的事情都是一样的,要minimize loss),在这个neural network里面参数的目标是不同的。label predictor做的事情是把class分类做的正确率越高越好,domain classifier做的事情是想正确predict image是属于哪个domain。feature extractor想要做的事情是:要同时improve label predictor,同时想要minimize domain classifier accuracy,所以feature extractor 其实是在做陷害队友这件事的。
feature extractor 怎样陷害队友呢(domain classifier)?这件事情是很容易的,你只要加一个gradient reversal layer就行了。也就是你在做back-propagation( Domain classifier 计算 back propagation 有 forward 跟 backward 两个 path ),在做backward task的时候你的domain classifier传给feature extractor什么样的value,feature extractor就把它乘上一个负号。也就是domain classifier 告诉你说某个value要上升,它就故意下降。

domain classifier因为看不到真正的image,所以它最后一定fail掉。因为它所能看到的东西都是feature extractor告诉它的,所以它最后一定会无法分辨feature extractor所抽出来的feature是来自哪个domain。
这个 model 原理讲起来很简单,但可能实际上的 training 可能跟 GAN 一样是没有那么好 train 的,问题就是domain classifier一定要奋力的挣扎,因为它要努力去判断现在的feature是来自哪个domain。如果 domain classifier 他比较弱、懒惰,他一下就放弃不想做了,就没有办法把前面的 feature extractor 逼到极限,就没有办法让 feature extractor 真的把 domain information remove 掉。如果 domain classifier 很 weak,他一开始就不想做了,他 output 永远都是 0 的话,那 feature extractor 胡乱弄什么 feature 都可以骗过 classifier 的话,那就达不到把 domain 特性 remove 掉的效果,这个 task 一定要让 domain classifier 奋力挣扎然后才死掉,这样才能把 feature extractor 的潜能逼到极限。

这是 paper 一些实验的结果,做不同 domain 的 transfer。如果看实验结果的话,纵轴代表用不同的方法,这边有一个 source only 的方法,直接在 source domain 上 train 一个 model,然后 test 在 target domain 上,如果只用 source only 的话,Performance 是比较差的。这边比较另一个 transfer learning 的方法,大家可以自己去看参考文献。这篇paper proposed 的方法是刚刚讲的 domain-adversarial training。
直接拿 target domain 的 data 去做 training,会得到 performance 是最下面这个 row,这其实是 performance 的 upper bound。用 source data 跟 target data train 出来的结果是天差地远的,这中间有一个很大的 gap。
如果用 domain-adversarial training 可以在不同的 case 上面都有很好的 improvement。
在zero-shot-learning里面跟刚才讲的task是一样的,source data有label,target data没有label。
在刚才task里面可以把source data当做training data,把target data当做testing data,但是实际上在zero-shot learning里面,它的define又更加严格一点。它的define是:今天在source data和target data里面,它的task是不一样的。
比如说在影像上面(你可能要分辨猫跟狗),你的source data可能有猫的class,也有狗的class。但是你的target data里面image是草泥马,在source data里面是从来没有出现过草泥马的,如果machine看到草泥马,就未免有点强人所难了。但是这个task在语音上很早就有solution了,其实语音是常常会遇到zero-shot learning的问题。

假如我们把不同的word都当做一个class的话,那本来在training的时候跟testing的时候就有可能看到不同的词汇。你的testing data本来就有一些词汇是在training的时候是没有看过的。
那在语音上我们如何来解决这个问题呢?不要直接去辨识一段声音是属于哪一个word,我们辨识的是一段声音是属于哪一个phoneme。然后我们在做一个phoneme跟table对应关系的表,这个东西也就是lexicon(词典)。在辨识的时候只要辨识出phoneme就好,再去查表说:这个phoneme对应到哪一个word。
这样就算有一些word是没有在training data里面的,它只要在lexicon里面出现过,你的model可以正确辨识出声音是属于哪一个phoneme的话,你就可以处理这个问题。

在影像上我们可以把每一个class用它的attribute来表示,也就是说:你有一个database,这个database里面会有所以不同可能的object跟它的特性。假设你要辨识的是动物,但是你training data跟testing data他们的动物是不一样的。但是你有一个database,这个database告诉你说:每一种动物它是有什么样的特性。比如狗就是毛茸茸,四只脚,有尾巴;鱼是有尾巴但不是毛茸茸,没有脚。
这个attribute要更丰富,每一个class都要有不一样的attribute(如果两个class有相同的attribute的话,方法会fail掉)。那在training的时候,我们不直接辨识每一张image是属于哪一个class,而是去辨识:每一张image里面它具备什么样的attribute。所以你的neural network target就是说:看到猩猩的图,就要说:这是一个毛茸茸的动物,没有四只脚,没有尾巴。看到狗的图就要说:这是毛茸茸的动物,有四只脚,有尾巴。

那在testing的时候,就算今天来了你从来没有见过的image,也是没有关系的。你今天neural network target也不是input image判断它是哪一种动物,而是input这一张image判断具有什么样的attribute。所以input你从来没有见过的动物,你只要把它的attribute找出来,然后你就查表看说:在database里面哪一种动物它的attribute跟你现在model output最接近。有时可能没有一摸一样的也是没有关系的,看谁最接近,那个动物就是你要找的。

那有时候你的attribute可能非常的复杂(attribute dimension非常大),你可以做attribute embedding。也就是说现在有一个embedding space,把training data每一个image都通过一个transform,变成一个embedding space上的一个点。然后把所有的attribute也都变成embedding space上的一个点,这个跟都可以是neural network,那training的时候希望f跟g越接近越好。那在testing的时候如果有一张没有看过的image,你就可以说这张image attribute embedding以后跟哪个attribute最像,那你就可以知道它是什么样的image。
image跟attribute都可以描述为vector,要做的事情就是把attribute跟image都投影到同一个空间里面。也就是说:你可以想象成是对image的vector,也就是图中的x,跟attribute的vector,也就是图中的y都做降维,然后都降到同一个dimension。所以你把x通过一个function f都变成embedding space上的vector,把y通过另外一个function g也都变成embedding space上的vector。
但是咋样找这个f跟g呢?你可以说f跟g就是neural network。input一张image它变成一个vector,或者input attribute 变成一个vector。training target是你希望说:假设我们已经知道是的attribute,是的attribute,那你就希望说找到一个f跟g,它可以让跟投影到embedding space以后越接近越好,跟投影到embedding space以后越接近越好。
那现在把f跟g找出来了,那现在假如有一张你从来没见过的image 在你的testing data里面,它也可以通过这个f变成embedding space上面的一个vector,接下来你就可以说这个embedding vector它跟最接近,那就是它的attribute,再来确定是哪个动物。

又是你会遇到一个问题,如果我没有database呢?我根本不知道每一个动物的attribute是什么,怎么办呢?
可以借用 word vector,word vector 的每一个 dimension 就代表了现在这个 word的某种 attribute。所以不一定需要有个 database 去告诉你每一个动物的 attribute 是什么。假设有一组 word vector,这组 word vector
里面你知道每个动物他对应的 word 的 word vector,这 word vector 你可以拿一个很大的 corpus,比如说 Wikipedia train 出来,就可以把 attribute 直接换成 word vector,所以把 attribute 通通换成那个 word 的 word vector,再做跟刚才一样的 embedding,就结束了。

这个loss function存在些问题,它会让model把所有不同的x和y都投影到同一个点上:
类似用t-SNE的思想,我们既要考虑同一对和距离要接近,又要考虑不属于同一对的与距离要拉大(这是前面的式子没有考虑到的),于是有:
0loss的情况是:跟之间的inner product大过所有其它的跟之间的inner product,而且要大过一个margin k

还有另外一个简单的Zero-Shot learning的方法叫做convex combination of semantic embedding。这个方法是说:在这边不需要做任何 training,就可以做 transfer learning。假设有一个 off-the-shelf 识别系统,跟一个 off-the-shelf 的 word vector。这两个可能不是自己 train,或网络上载下来的。
我把一张图丢到neural network里面去,它的output没有办法决定是哪一个class,但它觉得有0.5的机率是lion,有0.5的机率是tiger。接下来去找lion跟tiger的word vector,然后把 lion 跟 tiger 的 word vector 用 1:1 的比例混合,0.5 tiger 的 vector 加 0.5 lion 的 vector,得到另外一个新的 vector。再看哪个word的vector跟这个混合之后的结果最接近。假设是liger最接近,那这个东西就是liger。
在training的时候,machine看过如何把英文翻译成韩文,知道咋样把韩文翻译为英文,知道咋样把英文翻译为日文,知道咋样把日文翻译为英文。但是它从来没有看过日文翻译韩文的data,但是可以翻,但是它从来没有看过韩文翻译日文的data,但是可以翻。
为什么zero-shot在这个task上是可行的呢?如果你今天用同一个model做了不同语言之间的translation以后,machine可以学到的事情是:对不同语言的input 句子都可以project到同一个space上面。
在training的时候,machine看过如何把英文翻译成韩文,知道咋样把韩文翻译为英文,知道咋样把英文翻译为日文,知道咋样把日文翻译为英文。但是它从来没有看过日文翻译韩文的data,但是可以翻,但是它从来没有看过韩文翻译日文的data,但是可以翻。
为什么zero-shot在这个task上是可行的呢?如果你今天用同一个model做了不同语言之间的translation以后,machine可以学到的事情是:对不同语言的input 句子都可以project到同一个space上面。
我们现在根据我们learn好的translation,那个translation有一个encoder,它会把你input的句子变成vector,decoder根据这个vector解回一个句子,就是翻译的结果。那今天我们把不同语言都丢到这个encoder里面让它变成vector的话,那这些不同语言的不同句子在这个space上面有什么不一样的关系呢?

它发现说今天有日文、英文、韩文这三个句子,这三个句子讲的是同一件事情,通过encoder embedding以后再space上面其实是差不多的位置。在左边这个图上面不同的颜色代表说:不同语言的用一个意思的句子。所以你这样说:machine发明了一个新语言也是可以接受的,如果你把这个embedding space当做一个新的语言的话。machine做的是:发现可一个sequence language,每一种不同的语言都先要先转成它知道的sequence language,在用这个sequence language转为另外一种语言。
所以今天就算是某一个翻译task ,你的input语言和output语言machine没有看过,它也可以通过过这种自己学出来的sequence language来做translation。
刚刚讲的状况都是 source data 有 label 的状况,有时候会遇到 source data 没有 label 的状况。
target data 有 label,source data 没有 label,这种是 Self-taught learning
target data 没有 label,source data 也没有 label,这种是 Self-taught clustering
有一个要强调的是 Self-taught learning 跟 source data 是 unlabeled data,target data 是 labeled data
这也是一种 semi-supervised learning。这种 semi-supervised learning 跟一般 semi-supervised learning 有一些不一样,一般 semi-supervised learning 会假设那些 unlabeled data 至少还是跟 labeled data是比较有关系的。但在 Self-taught learning 里面,那些 unlabeled data、那些 source data,跟 target data 关系比较远。
其实 Self-taught learning 概念很简单,假设 source data 够多,虽然它是 unlabeled,可以去 learn 一个 feature extractor,在原始的 Self-taught learning paper 里面,他的 feature extractor 是 sparse coding。因为这 paper 比较旧,大概十年前,现在也不见得要用 sparse coding 也可以 learn,比如说 auto-encoder。
总之,有大量的 data,他们没有 label,可以做的是用这些 data learn 一个好的 feature extractor,learn 一个好的 representation。用这个 feature extractor 在 target data 上面去抽 feature。
在 Self-taught learning 原始的 paper 里面,其实做了很多 task,这这些 task 都显示 Self-taught learning 是可以得到显著 improvement的。
Learning to extract better representation from the source data (unsupervised approach)
Extracting better representation for target data

Meta learning 总体来说就是让机器学习如何学习。

如上图,我们希望机器在学过一些任务以后,它学会如何去学习更有效率,也就是说它会成为一个更优秀的学习者,因为它学会了学习的技巧。举例来说,我们教机器学会了语音辨识、图像识别等模型以后,它就可以在文本分类任务上做的更快更好,虽然说语音辨识、图像识别和文本分类没什么直接的关系,但是我们希望机器从先前的任务学习中学会了学习的技巧。
讲到这里,你可能会觉得Meta Learning 和 Life-Long Learning 有点像,确实很像,但是 Life-Long Learning 的着眼点是用同一个模型apply 到不同的任务上,让一个模型可以不断地学会新的任务,而Meta Learning 中不同的任务有不同的模型,我们的着眼点是机器可以从过去的学习中学到学习的方法,让它在以后的学习中更快更好。
我们先来看一下传统的ML 的做法:

我们过去学过的ML ,通常来说就是定义一个学习算法,然后用训练数据train ,吐出一组参数(或者说一个参数已定的函数式),也就是得到了模型,这个模型可以告诉我们测试数据应该对应的结果。比如我们做猫狗分类,train 完以后,给模型一个猫的照片,它就会告诉我们这是一只猫。
我们把学习算法记为 ,这个学习算法吃training data 然后吐出目标模型 ,形式化记作:
Meta Learning 就是要让机器自动的找一个可以吃training data 吐出函数 的函数 。
总结一下:

Machine Learning 和Meta Learning 都是让机器找一个function ,只不过要找的function 是不一样的。
我们知道Machine Learning 一共分三步(如下图),Meta Learning 也是一样的,你只要把Function 换成学习的算法 这就是Meta Learning 的步骤:
所以接下来我们将分三部分来讲Meta Learning 的具体过程。

什么是一组learning algorithm 呢?

如上图所示,灰色框中的,包括网络(模型)架构,初始化参数的方法,更新参数的方法,学习率等要素构成的整个process ,可以被称为一个learning algorithm 。在训练的过程中有很多要素(图中的红色方框)都是人设计的,当我们选择不同的设计的时候就相当于得到了不同的learning algorithm 。现在,我们考虑能不能让机器自己学出某一环节,或者全部process 的设计。比如说,我们用不同的初始化方法得到不同的初始化参数以后,保持训练方法其他部分的相同,且用相同的数据来训练模型,最后都会得到不同的模型,那我们就考虑能不能让机器自己学会初始化参数,直接得到最好的一组初始化参数,用于训练。
我们就希望通过Meta Learning 学习到初始化参数这件事,好,现在我们有了一组learning algorithm ,其中各个算法只有初始化参数的方法未知,是希望机器通过学习得出来的。
那现在我们怎么衡量一个learning algorithm 的好坏呢?

我们需要很多个task,每个task都有training set 和testing set,然后就把learning algorithm 应用到每个task上,用training set 训练,用testing set 测试,得到每一个task 的loss ,对于一个learning algorithm 的整体loss 就可以用每个task 的loss 进行求和。
从这里我们就能看出,meta learning 和传统的machine learning 在训练资料上是有些不同的:

做meta learning 的话你可能需要准备成百上千个task,每个task 都有自己的training set 和testing set 。这里为了区分,我们把meta learning的训练集叫做Training Tasks,测试集叫做Testing Tasks,其中中每个task 的训练集叫做Support set ,测试集叫做 Query set 。
Widely considered in few-shot learning,常常和few-shot learning搭配使用
讲到这里你可能觉得比较抽象,后面会讲到实际的例子,你可能就理解了meta learning 的实际运作方法。Meta learning 有很多方法,加下来会讲几个比较常见的算法,本节课会讲到一个最有名的叫做MAML ,以及MAML 的变形叫做Reptile 。
定好了loss function 以后我们就要找一个最好的 ,这个可以使所有的training tasks 的loss 之和最小,形式化的写作下图下面的公式(具体计算方法后面再讲):

现在我们就有了meta learning 的algorithm ,我们可以用testing tasks 测试这个。把测试任务的训练集放丢入Learning Algorithm ,就会得到一个 ,再用测试任务的测试集去计算这个 的loss ,这个loss 就是整个meta learning algorithm 的loss ,来衡量这个方法的好坏。

这是一个corpus,这里面有一大堆奇怪的符号,总共有1623个不同的符号,每个符号有20个不同的范例。上图下侧就是那些符号,右上角是一个符号的20个范例。

N-ways K-shot classification 的意思是,分N个类别,每个类别有K个样例。
所以,20 ways 1shot 就是说分20类,每类只有1个样例。这个任务的数据集就例如上图中间的20张support set 和1张query set 。
把符号集分为训练符号集和测试符号集
这两个大概是最近(2019年)比较火的吧,Reptile 可以参考一下openai的这篇文章。
MAML
Reptile
MAML要做的就是学一个初始化的参数。过去你在做初始化参数的时候你可能要从一个distribution 中sample 出来,现在我们希望通过学习,机器可以自己给出一组最好的初始化参数。

做法就如上图所示,我们先拿一组初始化参数 去各个training task 做训练,在第n个task 上得到的最终参数记作 ,而 代表第n个task 在其testing set 上的loss,此时整个MAML 算法的Loss 记作:
这里提示一下,MAML就是属于需要所有任务的网络架构相同的meta learning algorithm,因为其中所有的function 要共用相同的初始化参数 。
那怎么minimize 呢?
答案就是Gradient Descent,你只要能得到 对 的梯度,那就可以更新 了,结束。
这里我们先假装已经会算这个梯度了,先把这个梯度更新参数的思路理解就好,我们先来看一下MAML 和 Model Pre-training 在Loss Function 上的区别。

通过上图我们仔细对比两个损失函数,可以看出,MAML是根据训练完的参数 计算损失,计算的是训练好的参数在各个task 的训练集上的损失;而预训练模型的损失函数则是根据当前初始化的参数计算损失,计算的是当前参数在要应用pre-training 的task 上的损失。
再举一个形象一点的例子:

(横轴是模型参数,简化为一个参数,纵轴是loss)
如上图说的,我们在意的是这个初始化参数经过各个task 训练以后的参数在对应任务上的表现,也就是说如果初始参数 在中间位置(如上图),可能这个位置根据当前参数计算的总体loss 不是最好的,但是在各个任务上经过训练以后 都能得到较低的loss(如 、),那这个初始参数 就是好的,其loss 就是小的。
反之,在Model pre-training 上:

我们希望直接通过这个 计算出来的各个task 的loss 是最小的,所以它的取值点就可能会是上图的样子。此时在task 2上初始参数可能不能够被更新到global minima,会卡在local minima 的点 。
综上所述:

MAML 是要找一个 在训练以后具有好的表现,注重参数的潜力,Model Pre-training 是要找一个 在训练任务上得到好的结果,注重现在的表现。

在MAML 中我们假设只update 参数一次。所以在训练阶段,你只做one-step training ,参数更新公式就变成
只更新一次是有些理由的:

我们只要sample 不同的a, b就可以得到不同的目标函数。
来看看对比结果:

可以看到,预训练模型想要让参数在所有的training task上都做好,也就是一大堆sin函数,多个task叠加起来,导致预训练模型的参数最后拟合得到的是一条直线。
MAML的结果直接用上去是绿色的线,在测试task 上training step 增加的过程中有明显的拟合效果提升。
在MAML 的原始论文中也把这个技术用于Omniglot & Mini-ImageNet

我们看上图下侧,MAML, first order approx 和 MAML 的结果很相似,那first order approx 是怎么做的呢?解释这个东西需要一点点数学:

MAML 的参数更新方法如上图左上角灰色方框所示,我们来具体看看这个 怎么算,把灰框第二条公式带入,如黄色框所示。其中 就是左下角所示,它就是loss 对初始参数集 的每个分量的偏微分。也就是说 的变化会通过 中的每个参数 ,影响到最终训练出来的 ,所以根据chain rule 你就可以把左下角的每个偏微分写成上图中间的公式。
上式中前面的项 是容易得到的,具体的计算公式取决于你的model 的loss function ,比如cross entropy 或者regression,结果的数值却决于你的训练数据的测试集。
后面的项 是需要我们算一下。可以分成两个情况来考虑:

根据灰色框中第三个式子,我们知道 可以用下式代替:
此时,对于 这一项,分为i=j 和 i!=j 两种情况考虑,如上图所示。在MAML 的论文中,作者提出一个想法,不计算二次微分这一项。如果不计算二次微分,式子就变得非常简单,我们只需要考虑i=j 的情况,i!=j 时偏微分的答案总是0。
此时, 就等于 。这样后一项也解决了,那就可以算出上图左下角 ,就可以算出上图黄色框 ,就可以根据灰色框第一条公式更新 ,结束。

在原始paper 中作者把,去掉二次微分这件事,称作using a first-order approximation 。
当我们把二次微分去掉以后,上图左下角的 就变成 ,所以我们就是再用 直接对 做偏微分,就变得简单很多。

实际上,我们在MAML 中每次训练的时候会拿一个task batch 去做。如上图,当我们初始化好参数 我们就开始进行训练,sample出task m,完成task m训练以后,根据一次update 得到 ,我们再计算一下 对它的loss function 的偏微分,也就是说我们虽然只需要update 一次参数就可以得到最好的参数,但现在我们update 两次参数, 的更新方向就和第二次更新参数的方向相同,可能大小不一样,毕竟它们的learning rate 不一样。
刚才我们讲了在精神上MAML 和Model Pre-training 的不同,现在我们来看看这两者在实际运作上的不同。如上图,预训练的参数更新完全和每个task 的gradient 的方向相同。
这里有一个把MAML 应用到机器翻译的例子:

18个不同的task:18种不同语言翻译成英文
2个验证task:2种不同语言翻译成英文
Ro 是validation tasks 中的任务,Fi 即没有出现在training tasks 也没出现在validation tasks,是test的结果
横轴是每个task 中的训练资料量。MetaNMT 是MAML 的结果,MultiNMT 是 Model Pre-training 的结果,我们可以看到在所有case上面,前者都好过后者,尤其是在训练资料量少的情况下,MAML 更能发挥优势。

做法就是初始化参数 以后,通过在task m上训练更新参数,可以多更新几次,然后根据最后的 更新 ,同样的继续,训练在task n以后,多更新几次参数,得到 ,据此更新 ,如此往复。
你可能会说,这不是和预训练很像吗,都是根据参数的更新来更新初始参数,希望最后的参数在所有的任务上都能得到很好的表现。作者自己也说,如上图下侧。

通过上图来对比三者在更新参数 的不同,似乎Reptile 在综合两者。但是Reptile 并没有限制你只能走两步,所以如果你多更新几次参数多走几步,或许Reptile 可以考虑到另外两者没有考虑到的东西。
上图中,蓝色的特别惨的线是pre-training ,所以说和预训练比起来meta learning 的效果要好一些。
上面所有的讨论都是在初始化参数这件事上,让机器自己学习,那有没有其他部分可以让机器学习呢,当然有很多。

比如说,学习网络结构和激活函数、学习如何更新参数......
Automatically Determining Hyperparameters
我们使用MAML 或Reptile 来寻找最好的初始化参数,但是这个算法本身也需要初始化参数,那我们是不是也要训练一个模型找到这个模型的初始化参数......
就好像说神话中说世界在乌龟背上,那这只乌龟应该在另一只乌龟背上......

传统的机器学习和深度学习的算法基本上都还是gradient descent ,你能不能做一个更厉害的算法,只要我们给他所有的training data 它就可以返回给我们需要model,它是不是梯度下降train 出来的不重要,它只要能给我一个能完成这个任务的model 就好。
或者,反之我们最后都要应用到测试集上,那我们干脆就搞一个大黑箱,把training set 和testing set 全部丢给他,它直接返回testing data 的结果,连测试都帮你做好。这些想法能不能做到,留到下一节讲。

上节课讲了MAML 和Reptile ,我们说Meta Learning 就是要让机器自己learn 出一个learning 的algorithm。今天我们要讲怎么把我们熟悉的learning algorithm :Gradient Descent ,当作一个LSTM 来看待,你直接把这个LSTM train下去,你就train 出了Gradient Descent 这样的Algorithm 。(也就是说我现在要把学习算法,即参数的更新算法当作未知数,用Meta Learning 训练出来)

上周我们讲的MAML 和Reptile 都是在Initial Parameters 上做文章,用Meta Learning 训练出一组好的初始化参数,现在我们希望能更进一步,通过Meta Learning 训练出一个好的参数update 算法,上图黄色方块。
我们可以把整个Meta Learning 的算法看作RNN,它和RNN 有点像的,同样都是每次吃一个batch 的data ,RNN 中的memory 可以类比到Meta Learning 中的参数 。
把这个Meta Learning 的算法看作RNN 的思想主要出自两篇paper :
Optimization as a Model for Few-Shot Learning | OpenReview
Sachin Ravi, Hugo Larochelle
[1606.04474] Learning to learn by gradient descent by gradient descent (arxiv.org) Marcin Andrychowicz, Misha Denil, Sergio Gomez, Matthew W. Hoffman, David Pfau, Tom Schaul, Brendan Shillingford, Nando de Freitas
第二篇文章的题目非常有趣,也说明了此篇文章的中心:让机器学习用梯度下降学习这件事,使用的方法就是梯度下降。
从与之前略微不同的角度快速回顾一下RNN。

RNN就是一个function ,这个函数吃 吐出 ,每个step 会有一个(训练样本数据)作为input,还有一个初始的memory 的值 作为input,这个初始参数有时候是人手动设置的,有时候是可以让模型learn 出来的,然后输出一个和一个 。到下一个step,它吃上一个step 得到的 和新的,也是同样的输出。需要注意的是,的维度都是一致的,这样同一个 才能吃前一个step 得到 。这个过程不断重复,就是RNN。
所以,无论多长的input/output sequence 我们只需要一个函数 就可以运算,无论你的输入再怎么多,模型的参数量不会变化,这就是RNN 厉害的地方,所以它特别擅长处理input 是一个sequence 的状态。(比如说自然语言处理中input 是一个长句子,用word vector 组成的很长的sequence)
我们如今用的一般都是RNN 的变形LSTM,而且我们现在说使用RNN 基本上就是在指使用LSTM 的技术。那LSTM 相比于RNN 有什么特别的地方呢。

如上图,LSTM(右)相比于RNN ,把input 的h 拆解成两部分,一部分仍然叫做 ,一部分我们叫做 。为什么要这样分呢,你可以想象是因为 和 扮演了不同的角色。
我们接下来看看LSTM 的做法和结构:

是memory 记忆单元,把和拼在一起乘上一个权重矩阵W,再通过一个tanh 函数得到input ,是一个向量。同样的x和h拼接后乘上对应的权重矩阵得到对应向量input gate ,forget gate ,output gate ,接下来:

决定是否保留上个memory, 决定是否把现在的input 存到memory;
通过 得到新的 ;
乘上新的 ,再通过一个sigmoid function 得到当前step 的output ;
重复上述步骤,就是LSTM 的运作方式:

好,讲了这么多,它和Gradient Descent 到底有什么样的关系呢?
我们把梯度下降参数θ更新公式和LSTM 的memory c更新公式都列出来,如下:
我们知道在gradient descent 中我们在每个step 中,把旧的参数减去,learning rate 乘梯度,作为更新后的新参数,此式和LSTM 中memory 单元 有些相似,我们就把 替换成 :

接下来我们再做一些变换。输入 来自上一个step, 来自外界输入,我们就把 换成 。然后我们假设从input 到 的公式中乘的matrix 是单位矩阵,所以 就等于 。再然后,我们把 定为全1的列向量, 定位全为learning rate 的列向量,此时LSTM 的memory 的更新公式变得和Gradient Descent 一样。
所以你可以说Gradient Descent 就是LSTM 的简化版,LSTM中input gate 和forget gate是通过机器学出来的,而在梯度下降中input gate 和forget gate 都是人设的,input gate 永远都是学习率,forget gate 永远都是不可以忘记。
现在,我们考虑能不能让机器自己学习gradient descent 中的input gate 和forget gate 呢?
另外,input的部分刚才假设只有gradient 的值,实作上可以拿更多其他的数据作为input,比如常见的做法,可以把 在现在这个step算出来的loss 作为输入来control 这个LSTM的input gate 和forget gate 的值。

如果们可以让机器自动的学input gate 和forget gate 的值意味着什么?意味着我们可以拥有动态的learning rate,每一个dimension在每一个step的learning rate 都是不一样的而不是一个不变的值。
而 就像一个正则项,它做的事情是把前一个step 算出来的参数缩小。我们以前做的L2 regularization 又叫做Weight Decay ,为什么叫Weight Decay,因为如果你把update的式子拿出来看,每个step 都会把原来的参数稍微变小,现在这个 就扮演了像是Weight Decay的角色。但是我们现在不是直接告诉机器要做多少Weight Decay,而是要让机器学出来,它应该做多少Weight Decay 。
我们来看看一般的LSTM和for Gradient Descent 的LSTM:

Typical LSTM 就是input x ,output c 和 h,每个step 会output 一个y ,希望y 和label 越接近越好。
Gradient Descent 的LSTM是这样:我们先sample 一个初始参数θ ,然后sample 一个batch 的data ,根据这一组data 算出一个gradient ,把负的gradient input 到LSTM 中进行训练,这个LSTM 的参数过去是人设死的,我们现在让参数在Meta Learning 的架构下被learn 出来。上述的这个update 参数的公式就是:
以前是人设死的,现在LSTM 可以自动把它学出来。
现在就可以output 新的参数 ,接着就是做一样的事情:再sample 一组数据,算出梯度作为新的input,放到LSTM 中就得到output ,以此类推,不断重复这个步骤。最后得到一组参数(这里假设只update 3次,实际上要update 更多次),拿这组参数去应用到Testing data 上算一下loss : ,这个loss 就是我们要minimize 的目标,然后你就要用gradient descent 调LSTM 的参数,去minimize 最后的loss 。
这里有一些需要注意的地方。在一般的LSTM 中 和 是独立的,LSTM 的memory 存储的值不会影响到下一次的输入,但是Gradient Descent LSTM 中参数会影响到下一个step 中算出的gradient 的值,如上图虚线所示。
所以说在Gradient Descent LSTM 中现在的参数会影响到未来看到的梯度。所以当你做back propagation 的时候,理论上你的error signal 除了走实线的一条路,它还可以走到 虚线这一条路,可以通过gradient 这条路更新参数。但是这样做会很麻烦,和一般的LSTM 不太一样了,一般的LSTM 和 是没有关系的,现在这里确实有关系,为了让它和一般的LSTM 更像,为了少改一些code ,我们就假设没有虚线那条路,结束。现在的文献上其实也是这么做的。
另外,在LSTM input 的地方memory 中的初始值可以通过训练直接被learn 出来,所以在LSTM中也可以做到和MAML相同的事,可以把初始的参数跟着LSTM一起学出来。
LSTM 的memory 就是要训练的network 的参数,这些参数动辄就是十万百万级别的,难道要开十万百万个cell 吗?平常我们开上千个cell 就会train 很久,所以这样是train不起来的。在实际的实现上,我们做了一个非常大的简化:我们所learn 的LSTM 只有一个cell 而已,它只处理一个参数,所有的参数都共用一个LSTM。所以就算你有百万个参数,都是使用这同一个LSTM 来处理。

也就是说如上图所示,现在你learn 好一个LSTM以后,它是直接被用在所有的参数上,虽然这个LSTM 一次只处理一个参数,但是同样的LSTM 被用在所有的参数上。 使用的LSTM 和 使用的LSTM 是同一个处理方式也相同。那你可能会说, 和 用的处理方式一样,会不会算出同样的值呢?会不,因为他们的初始参数是不同的,而且他们的gradient 也是不一样的。在初始参数和算出来的gradient 不同的情况下,就算你用的LSTM的参数是一样的,就是说你update 参数的规则是一样的, 最终算出来的也是不一样的 。
这就是实作上真正implement LSTM Gradient Descent 的方法。
这么做有什么好处:

我们来看一个文献上的实验结果,这是做在few-shot learning 的task上。横轴是update 的次数,每次train 会update 10次,左侧是forget gate 的变化,不同的红色线就是不同的task 中forget gate 的变化,可以看出 的值多数时候都保持在1附近,也就是说LSTM 有learn到是很重要的东西,没事就不要忘掉,只做一个小小的weight decay,这和我们做regularization 时候的思想相同,只做一个小小的weight decay 防止overfitting 。
右侧是input gate 的变化,红线是不同的task,可以看出它的变化有点复杂,但是至少我们知道,它不是一成不变的固定值,它是有学到一些东西的,是动态变化的,放到经典梯度下降中来说就是learning rate 是动态变化的。
只有刚才的架构还不够,我们还可以更进一步。想想看,过去我们在用经典梯度下降更新参数的时候我们不仅会考虑当前step 的梯度,我们还会考虑过去的梯度,比如RMSProp、Momentum 等。
在刚才的架构中,我们没有让机器去记住过去的gradient ,所以我们可以做更进一步的延伸。我们在过去的架构上再加一层LSTM,如下图所示:

蓝色的一层LSTM 是原先的算learning rate、做weight decay 的LSTM,我们再加入一层LSTM ,让算出来的gradient 先通过这个LSTM ,把这个LSTM 吐出来的东西input 到原先的LSTM 中,我们希望绿色的这一层能做到记住以前算过的gradient 这件事。这样,可能就可以做到Momentum 可以做的的事情。
上述的这个方法,是老师自己想象的,在learning to learn by gradient descent by gradient descent 这篇paper 中上图中蓝色的LSTM 使用的是一般的梯度下降算法,而在另一篇paper 中只有上面没有下面,而老师觉得这样结合起来才是合理的能考虑过去的gradient 的gradient descent 算法的完全体。
learning to learn by gradient descent by gradient descent 这篇paper 的实验结果。

第一个实验图,是做在toy example 上,它可以制造一大堆训练任务,然后测试在测试任务上,然后发现,LSTM 来当作gradient descent 的方法要好过人设计的梯度下降方法。
其他图中这个实验是训练任务测试任务都是MNIST。虽然训练和测试任务都是相同的dataset也是相同的,但是train 和test 的时候network 的架构是不一样的。 在train 的时候network 是只有一层,只有20个neuron。
第四张图是上述改变network 架构后在testing 的结果,testing 的时候network 只有一层该层40个neuron。从图上看还是做的起来,而且比一般的gradient descent 方法要好很多。
第五张图是上述改变network 架构后在testing 的结果,testing 的时候network 有两层。从图上看还是做的起来,而且比一般的gradient descent 方法要好很多。
第六张图是上述改变network 激活函数后在testing 的结果,training 的时候激活函数是sigmoid 而testing 的时候改成ReLU。从图上看做不起来,崩掉了,training 和testing 的network 的激活函数不一样的时候,LSTM 没办法跨model 应用。
加下来我们就要实践我们之前提到的疯狂的想法:直接学一个function,输入训练数据和对应的标签,以及测试数据,直接输出测试数据的预测结果。也就是说这个模型把训练和预测一起做了。
虽然这个想法听起很crazy,但是实际上现实生活中有在使用这样的技术,举例来说:手机的人脸验证

我们在使用手机人脸解锁的时候需要录制人脸信息,这个过程中我们转动头部,就是手机在收集资料,收集到的资料就是作为few-shot learning 的训练资料。另外,语音解锁Speaker Verification 也是一样的技术,只要换一下输入资料和network 的架构。

这里需要注意Face Verification 和Face Recognition 是不一样的,前者是说给你一张人脸,判定是否是指定的人脸,比如人脸验证来解锁设备;后者是辨别一个人脸是人脸集合里面谁,比如公司人脸签到打卡。
下面我们就以Face Verification 为例,讲一下Metric-based Meta Learning

训练任务集中的任务都是人脸辨识数据,每个任务的测试集就是某个人的面部数据,测试集就是按标准(如手机录制人脸)收集的人脸数据,如果这个人和训练集相同就打一个Yes 标签,否则就打一个No 标签。测试任务和训练任务类似。总的来说,network 就是吃训练的人脸和测试的人脸,它会告诉你Yes or No 。
测试任务要与训练任务有点不同,测试的脸应该没有出现在测试任务中。
实际上是怎么做的呢,使用的技术是Siamese Network(孪生网络)。

Siamese Network 的结构如上图所示,两个网络往往是共享参数的,根据需要有时候也可以不共享,假如说你现在觉得Training data 和Testing data 在形态上有比较大的区别,那你就可以不共享两个网络的参数。
从两个CNN 中抽出两个embedding ,然后计算这两个embedding 的相似度,比如说计算conference similarity 或者Euclidean Distance ,你得到一个数值score ,这个数值大就代表Network 的输出是Yes ,如果数值小就代表输出是No 。
接下来从直觉上来解释一下孪生网络。

如上图所示,你可以把Siamese Network 看成一个二分类器,他就是吃进去两张人脸比较一下相似度,然后告诉我们Yes or No 。这样解释会比从Meta Learning 的角度来解释更容易理解。

如上图所示,Siamese Network 做的事情就是把人脸投影到一个空间上,在这个空间上只要是同一个人的脸,不管机器看到的是他的哪一侧脸,都能被投影到这个空间的同一个位置上。同一个人距离越近越好,不同的人距离越远越好。
这种图片降维的方法,这和Auto-Encoder有什么区别呢,他比Auto-Encoder 好在哪?
你想你在做Auto-Encoder 的时候network不知道你要解的任务是什么,它会尽可能记住图片中所有的信息,但是它不知道什么样的信息是重要的什么样的信息是不重要的。
例子里面上图右侧,如果用Auto-Encoder 它可能会认为一花(左下)和三玖(右上)是比较接近的,因为他们的背景相似。在Siamese Network 中,因为你要求network 把一花(左下)和三玖(右上)拉远,把三玖(右上)和三玖(右下)拉近,它可能会学会更加注意头发颜色的信息,要忽略背景的信息。
计算两个embedding的相近度
What kind of distance should we use?
Triplet loss(三元是指:从训练集中选取一个样本作为Anchor,然后再随机选取一个与Anchor属于同一类别的样本作为Positive,最后再从其他类别随机选取一个作为Negative)
刚才的例子中,训练资料都只有一张,机器只要回答Yes or No 。那现在如果是一个分类的问题呢?现在我们打算把同样的概念用在5-way 1-shot 的任务上该怎么办呢?

5-way 1-shot 就是说5个类别,每个类别中只有1个样本。就比如说上图,《五等分花嫁》中的五姐妹,要训一个模型分辨一个人脸是其中的谁,而训练资料是每个人只有一个样本。我们期待做到的事情是,Network 就把这五张带标签的训练图片外加一张测试图片都吃进去,然后模型就会告诉我们测试图片的分辨结果。
那模型的架构要怎么设计呢,这是一个经典的做法:

这个方法和Siamese Network 非常相似,只不过从input 一张training data 扩展到input 多张training data 。
如上图所示,把每张图片丢到同一个CNN 中算出一个embedding 用橙色条表示,然后把测试图片的embedding 和所有训练图片的embedding 分别算出相似度 。黄色的方块表示计算相似度。
接下来,取一个softmax ,这样就可以和正确的标签做cross entropy ,去minimize cross entropy,这就和一般的分类问题的loss function相同的,就可以根据这个loss 做一次gradient descent ,因为是1-shot 所以只能做一次参数更新。
那如果是few-shot 呢,怎么用Prototypical Network 解决呢。如右上角,我们把每个类别的几个图片用CNN 抽出的embedding 做average 来代表这个类别就好了。进来一个Testing Data 我们就看它和哪个class 的average 值更接近,就算作哪一个class 。
Matching Network 和Prototypical Network 最不同的地方是,Matching Network 认为也许Training data 中的图片互相之间也是有关系的,所以用Bidirectional LSTM 处理Training data,把Training data 通过一个Bidirectional LSTM 也会得到对应的embedding ,然后的做法就和Prototypical Network 是一样的。

事实上是Matching Network 先被提出来的,然后人们觉得这个方法有点问题,问题出在Bidirectional LSTM 上,就是说如果输入Training data 的顺序发生变化,那得到的embedding 就变了,整个network 的辨识结果就可能发生变化,这是不合理的。

这个方法和上面讲过的很相似,只是说我们之前通过人定的相似度计算方法计算每一类图片和测试图片的相似度,而Relation Network 是希望用另外的模型 来计算相似度。
具体做法就是先通过一个 计算每个类别的以及测试数据的embedding ,然后把测试数据的embedding 接在所有类别embedding 后面丢入 计算相似度分数。
我们在做Few-Shot Learning 的时候的难点就是训练数据量太少了,那能不能让机器自己生成一些数据提供给训练使用呢。这就是Few-shot learning for Imaginary Data 的思想。
Learn 一个Generator ,怎么Learn 出这个Generator 我们先不管,你给Generator 一个图片,他就会生成更多图片,比如说你给他三玖面无表情的样子,他就会YY出三玖卖萌的样子、害羞的样子、生气的样子等等。然后把生成的图片丢到Network 中做训练,结束。
实际上,真正做训练的时候Generator 和Network 是一起training的,这就是Few-shot learning for Imaginary Data 的意思。
我们在讲Siamese Network 的时候说,你可以把Siamese Network 或其他Metric-based 的方法想成是Meta Learning ,但其实你是可以从其他更容易理解的角度来考虑这些方法。总的来说,我们就是要找一个function,这个function 可以做的到就是吃训练数据和测试数据,然后就可以吐出测试数据的预测结果。我们实际上用的Siamese Network 或者Prototypical Network 、Matching Network 等等的方法多可以看作我们为了实现这个目的做模型架构的变形。
现在我们想问问,有没有可能直接用常规的network 做出这件事?有的。
用LSTM 把训练数据和测试数据吃进去,在最后输出测试数据的判别结果。训练图片通过一个CNN 得到一个embedding ,这个embedding 和这个图片的label(one-hot vector)做concatenate(拼接)丢入LSTM 中,Testing data 我们不知道label 怎么办,我们就用0 vector 来表示,然后同样丢入LSTM ,得到output 结束。这个方法用常规的LSTM 是train 不起来的,我们需要修改LSTM 的架构,有两个方法,具体方法我们就不展开讲了,放出参考链接:
One-shot Learning with Memory-Augmented Neural Networks
https://arxiv.org/abs/1605.06065
A Simple Neural Attentive Meta-Learner
SNAIL和我们上面刚说过想法的是一样的,输入一堆训练数据给RNN 然后给他一个测试数据它输出预测结果,唯一不同的东西就是,它不是一个单纯的RNN ,它里面有在做回顾这件事,它在input 第二笔数据的时候会回去看第一笔数据,在input 第三笔数据的时候会回去看第一第二笔数据...在input 测试数据额时候会回去看所有输入的训练数据。
所以你会发现这件事是不是和prototypical network 和matching network 很相似呢,matching network 就是计算input 的图片和过去看过的图片的相似度,看谁最像,就拿那张最像的图片的label 当作network 的输出。SNAIL 的回顾过去看过的数据的做法就和matching network 的计算相似度的做法很像。
所以说,你虽然想用更通用的方法做到一个模型直接给出测试数据预测结果这件事,然后你发现你要改network 的架构,改完起了个名字叫SNAIL 但是他的思想变得和原本专门为这做到这件事设计的特殊的方法如matching network 几乎一样了,有点殊途同归的意思。
开始之前的说明,如果读者是学过transfer learning 的话,学这一节可能会轻松很多,LLL的思想在我看来是和transfer learning是很相似的。
可以直观的翻译成终身学习,我们人类在学习过程中是一直在用同一个大脑在学习,但是我们之前讲的所有机器学习的方法都是为了解决一个专门的问题设计一个模型架构然后去学习的。所以,传统的机器学习的情景和人类的学习是很不一样的,现在我们就要考虑为什么不能用同一个模型学会所有的任务。
也有人把Life Long Learning 称为Continuous Learning,Never Ending Learning,Incremental Learning,在不同的文献中可能有不同的叫法,我们只要知道这些方法都是再指终生学习就可。
我想大多数人在学习机器学习之前的是这样认为的,我们教机器学学会任务1,再教会它任务2,我们就不断地较它各种任务,学到最后它就成了天网。但是实际上我们都知道,现在的机器学习是分开任务来学的,就算是这样很多任务还是得不到很好的结果。所以机器学习现在还是很初级的阶段,在很多任务上都无法胜任。
我们今天分三个部分来叙述Life-Long Learning:
Knowledge Retention 知识保留
Knowledge Transfer 知识潜移
Model Expansion 模型扩展
知识保留,但不顽固
知识保留但不顽固的精神是:我们希望模型在做完一个任务的学习之后,在学新的知识的时候,能够保留对原来任务能力,但是这种能力的保留又不能太过顽固以至于不能学会新的任务。
我们举一个例子看看机器的脑洞有多大。这里是影像辨识的例子,来看看在影像辨识任务中是否需要终身学习。
我们有两个任务,都是在做手写数字辨识,但是两个的corpus 是不同的(corpus1 图片上存在一些噪声)。network 的架构是三层,每层都是50个neuron,然后让机器先学任务1,学完第一个任务以后在两个corpus 上进行测试,得到的结果task1: 90%;task2: 96%(task2的结果更好一点其实是很直觉的,因为corpus2上没有noise,这可以理解为transfer learning)。然后我们在把这个模型用corpus2 进行一波训练,再在两个corpus上进行测试得到的结果task1: 80%;task2: 97%,发现第一个任务有被遗忘的现象发生。
这时候你可能会说,这个模型的架构太小了,他只有三层每层只有50个neuron,会发生遗忘的现象搞不好是因为它脑容量有限。但是我们实践过发现并不是模型架构太小。我们把两个corpus 混到一起用同样的模型架构train 一发,得到的结果task1: 89%;task2: 98%
所以说,明明这个模型的架构可以把两个任务都学的很好,为什么先学一个在学另一个的话会忘掉第一个任务学到的东西呢。
问答系统要做的事情是训练一个Deep Network ,给这个模型看很多的文章和问题,然后你问它一个问题,他就会告诉你答案。具体怎么输入文章和问题,怎么给你答案,怎么设计网络,不展开。
对于QA系统已经被玩烂的corpus 是bAbi 这个数据集,这里面有20种不同的题型,比如问where、what 等。可以分别用20个模型解题,也可以用1个模型同时解20个题型。我们训练一个模型从第一个题型开始学习,依次学完20种题型,每次学习完成以后我们都用题型五做一次测试,也就是以题型五作为baseline,结果如下:

我们可以看到只有在学完题型五的时候,再问机器题型五的问题,它可以给出很好的答案,但是在学完题型六以后它马上把题型五忘的一干二净了。这个现象在以其他的题型作为baseline 的时候同样出现了。
有趣的是,在题型10作为baseline 的时候可能是由于题型6、9、17、18和题型10比较相似,所以在做完这些题型的QA任务的时候在题型10上也能得到比较好的结果。
那你又会问了,是不是因为网络的架构不够大,机器的脑容量太小以至于学不起来。其实不是,当我们同时train这20种题型得到的结果是还不错的。

所以机器的遗忘是和人类很不一样的,他不是因为脑容量不够而忘记的,不知道为什么它在学过一些新的任务以后就会较大程度的遗忘以前学到的东西,这个状况我们叫做Catastrophic Forgetting(灾难性遗忘)。之所以加个形容词是因为这种遗忘是不可接受,只要学新的东西旧的东西就都出来了。
你可能会说这个灾难性遗忘的问题你上面不是已经有了一个很好的解决方法了吗,你只要把多个任务的corpus 放在一起train 就好了啊。

但是,长远来说这一招是行不通的,因为我们很难一直维护所有使用过的训练数据;而且就算我们很好的保留了所有数据,在计算上也有问题,我们每次学新任务的时候就要重新训练所有的任务,这样的代价是不可接受的。
另外,多任务同时train 这个方法其实可以作为LLL的上界。
我们期待的是,不做Multi-task training的情况下,让机器不要忘记过去学过的东西。
那这个问题有什么样的解法呢,接下来就来介绍一个经典解法。
基本精神:网络中的部分参数对先前任务是比较有用的,我们在学新的任务的时候只改变不重要的参数。

如上图所示, 是模型从先前的任务中学出来的参数。
每个参数 都有一个守卫 ,这个守卫就会告诉我们这个参数有多重要,我们有多么不能更改这个参数。
我们在做EWC 的时候(train 新的任务的时候)需要再原先的损失函数上加上一个regularization ,如上图所示,我们通过平方差的方式衡量新的参数 和旧的参数 的差距,然后乘上守卫,把所有参数加起来。
我们学习新的任务时,不止希望把新的任务做好,也希望新的参数和旧的参数差别不要太大,这种限制对每个参数是不同的:当这个守卫 等于零的时候就是说参数 是没有约束的,可以根据当前任务随意更改,当守卫 趋近于无穷大的时候,说明这个参数 对先前的任务是非常重要的,希望模型不要变动这个参数。

所以现在问题是, 如何决定。这个问题我们下面来讲,先来通过一个简单的例子再理解一下EWC的思想:

上图是这样的,假设我们的模型只有两个参数,这两个图是两个task 的error surface ,颜色越深loss 越大。假如说我们让机器学task1的时候我们的参数从 移动到 ,然后我们又让机器学task2,在这学这个任务的时候我们没有加任何约束,它学完之后参数移动到了 ,这时候模型参数在task1的error surface 上就是一个不太好的点。 这就直观的解释了为什么会出现Catastrophic Forgetting 。
当我们使用EWC 对模型的参数的变化做一个限制,就如上面说的,我们给每个参数加一个守卫 ,这个 是这么来的呢?

不同文章有不同的做法,这里有一个简单的做法就是算这个参数的二次微分(loss对的二次微分体现参数loss变化的剧烈程度,二次微分值越大,原函数图像在该点变化越剧烈),如上图所示。我们可以看出, 在二次微分曲线的平滑段其变化不会造成原函数图像的剧烈变化,我们要给它一个小的守卫 , 反之 则在谷底其变化会造成二次微分值的增大,导致原函数的变化更剧烈,我们要给它一个大的守卫 。也就是说, 可以动, 尽量别动。
有了上述的constraint ,我们就能让模型参数尽量不要在 方向上移动,可以在 上移动,得到的效果可能就会是这样的:

我们来看看EWC的原始paper中的实验结果:

三个task其实就是对MNIST 数据集做不同的变换后做辨识任务。每行是模型对该行的task准确率的变化,从第一行可以看出,当我们用EWC的方法做完三个任务学习以后仍然能维持比较好的准确率。值得注意的是,在下面两行中,L2的方法在学习新的任务的时候发生了Intransigence(顽固)的现象,就是模型顽固的记住了以前的任务,过于保守,而无法学习新的任务。
有很多EWC 的变体,给几个参考:
Elastic Weight Consolidation (EWC)
Synaptic Intelligence (SI)
Memory Aware Synapses (MAS)
上面我们说Mutli-task Learning 虽然好用,但是由于存储和计算的限制我们不能这么做,所以采取了EWC 等其他方法,而Mutli-task Learning 可以考虑为Life-Long Learning 的upper bound。 反过来我们不禁在想,虽然说要存储所有过去的资料很难,但是Multi-task Learning 确实那么好用,那我们能不能Learning 一个model,这个model 可以产生过去的资料,所以我们只要存一个model 而不用存所有训练数据,这样我们就做Multi-task 的learning。(这里暂时忽略算力限制,只讨论数据生成问题)

这个过程是这样的,我们先用training data 1 训练得到解决task 1 的model,同时用这些数据生成train 一个能生成这些数据的generator ,存储这个generator 而不是存储training data ;当来了新的任务,我们就用这个generator 生成task 1的training data 和 task2 的training data 混在一起,用Multi-task Learning 的方法train 出能同时解决task1 和task2 的model,同时我们用混在一起的数据集train 出一个新的generator ,这个generator 能生成这个混合数据集;以此类推。这样我们就可以做Mutli-task Learning ,而不用存储大量数据。但是这个方法在实际中到底能不能做起来,还尚待研究,一个原因是实际上生成数据是没有那么容易的,比如说生成贴合实际的高清的影像对于机器来说就很难,所以这个方法是否做的起来还是一个尚待研究的问题。
在刚才的讨论中,我们都是假设解不同的任务用的是相同的网络架构,但是如果现在我们的task 是不同,需要我们更改网络架构的话要怎么办呢?比如说,两个分类任务的class数量不同,我们就要修改network 的output layer 。这里就列一些参考给大家:

我们不仅希望机器可以可以记住以前学的knowledge ,我们还希望机器在学习新的knowledge 的时候能把以前学的知识做transfer。
Train a model for each task?
我们之前都是每个任务都训练一个单独的模型,这种方式会损失一个很重要的信息,就是解决不同问题之间的通用知识。形象点来说,比如你先学过线性代数和概率论,那你在学机器学习的时候就会应用先前学过的知识,学起来就会很顺利。我们希望机器可以学完某些task后,可以在之后的task学习中更加顺利,希望机器能够把不同任务之间的知识进行迁移,让以前学过的知识可以应用到解决新的任务上面。
讲了这么多,你可能会说,这不就是在做transfer Learning 吗?
Transfer Learning 的精神是应用先前任务的模型到新的任务上,让模型可以解决或者说更好的解决新的任务,而不在乎此时模型是否还能解决先前的任务;
但是LLL 就比Transfer Learning 更进一步,它会考虑到模型在学会新的任务的同时,还不能忘记以前的任务的解法。
讲到这里,我们来说一下如何衡量LLL 的好坏。其实,有很多不同的的衡量方法,这里简介一种。

这里每一行是一个模型在不同任务上的测试结果,每一列是用一个任务对一个模型在做完某些任务的训练以后进行测试的结果。
: 在训练完task i 后,模型在task j 上的performance 。
如果 : 在学完task i 以后,模型在先前的task j 上的performance。
如果 : 在学完task i 以后,模型在没学过的task j 上的performance,来说明前面学完的 i 个task 能不能transfer 到 task j 上。
Accuracy
Backward Transfer ,(It is usually negative.)
Forward Transfer
Accuracy 是指说机器在学玩所有T 个task 以后,在所有任务上的平均准确率,所以如上图红框,就把最后一行加起来取平均就是现在这个LLL model 的Accuracy ,形式化公式如上图所示。
Backward Transfer 是指机器有多会做Knowledge Retention(知识保留),有多不会遗忘过去学过的任务。做法是针对每一个task 的测试集(每列),计算模型学完T 个task 以后的performance 减去模型刚学完对应该测试集的时候的performance ,求和取平均,形式化公式如上图所示。
Backward Transfer 的思想就是把机器学到最后的表现减去机器刚学完那个任务还记忆犹新的表现,得到的差值通常都是负的,因为机器总是会遗忘的,它学到最后往往就一定程度的忘记以前学的任务,如果你做出来是正的,说明机器在学过新的知识以后对以前的任务有了触类旁通的效果,那就很强。

Forward Transfer 是指机器有多会做Knowledge Transfer (知识迁移),有多会把过去学到的知识应用到新的任务上。做法是对每个task 的测试集,计算模型学过task i 以后对task i+1 的performance 减去随机初始的模型在task i+1 的performance ,求和取平均。
上述的Backward Transfer 让这个值是正的就说明,model 不仅没有遗忘过学过的知识,还在学了新的知识以后对以前的任务触类旁通,这件事是有研究的,比如GEM 。
GEM 想做到的事情是,在新的task 上训练出来的gradient 在更新的参数的时候,要考虑一下过去的gradient ,使得参数更新的方向至少不能是以前梯度的方向(更新参数是要向梯度的反方向更新)。
需要注意的是,这个方法需要我们保留少量的过去的数据,以便在train 新的task 的时候(每次更新参数的时候)可以计算出以前的梯度。

形象点来说,以上图为例,左边,如果现在新的任务学出来的梯度是 ,那更新的时候不会对以前的梯度 造成反向的影响;右边,如果现在新的情况是这样的,那梯度在更新的时候会影响到, 和 的内积是负的,意味着梯度 会把参数拉向 的反方向,因此会损害model 在task 1上的performance。所以我们取一个尽可能接近 的 ,使得 和两个过去任务数据算出来的梯度的内积都大于零。这样的话就不会损害到以前task 的performance ,搞不好还能让过去的task 的loss 变得更小。
我们来看看GEM 的效果:

but parameter efficiency
上面讲的内容,我们都假设模型是足够大的,也就是说模型的参数够多,它是有能力把所有任务都做好,只不过因为某些原因它没有做到罢了。但是如果现在我们的模型已经学了很多任务了,所有参数都被充分利用了,他已经没有能力学新的任务了,那我们就要给模型进行扩张。同时,我们还要保证扩张不是任意的,而是有效率的扩张,如果每次学新的任务,模型都要进行一次扩张,那这样的话model会扩张的太快导致你最终就会无法存下你的模型,而且臃肿的模型中大概率很多参数都是没有用的。
这个问题在2018年老师讲课的时候还没有很多文献可以参考,存在的模型也都做的不是特别好。

这个方法是这样的,我们在学task 1的时候就正常train,在学task 2的时候就搞一个新的network ,这个网路不仅会吃训练集数据,而且会把训练集数据input 到task 1的network中得到的每层输出吃进去,这时候是fix 住task 1 network,而调整task 2 network 。同理,当学task 3的时候,搞一个新的network ,这个网络不仅吃训练集数据,而且会把训练集数据丢入task 1 network 和 task 2 network ,将其每层输出吃进去,也是fix 住前两个network 只改动第三个network 。
这是一个早期的想法,2016年就出现了,但是这个方法终究还是不太能学很多任务。
https://arxiv.org/abs/1611.06194
Aljundi, R., Chakravarty, P., Tuytelaars, T.: Expert gate: Lifelong learning with a network of
experts. In: CVPR (2017)
思想是这样的:每一个task 训练一个network 。
但是train 了另一个network ,这个network 会判断新的任务和原先的哪个任务最相似,加入现在新的任务和T1 最相似,那他就把network 1最为新任务的初始化network,希望以此做到知识迁移。
但是这个方法还是每一个任务都会有一个新的network ,所以还是不太好。

如果我们在增加network 参数的时候直接增加神经元进去,可能会破坏这个模型原来做的准确率,那我们怎么增加参数才能保证不会损害模型在原来任务上的准确率呢?Net2Net 是一个解决方法:

Net2Net的具体做法是这样的,如上图所示,当我么你要在中间增加一个neuron 时,我们把f 变为f/2 ,这样的话同样的输入在新旧两个模型中得到的输出就还是相同的,同时我们也增加了模型的参数。但是这样做出现一个问题,就是h[2] h[3] 两个神经元将会在后面更新参数的时候完全一样,这样的话就相当于没有扩张模型,所以我们要在这些参数上加上一个小小的noise ,让他们看起来还是有小小的不同,以便更新参数。
图中引用的文章就用了Net2Net,需要注意,不是来一个任务就扩张一次模型,而是当模型在新的任务的training data 上得不到好的Accuracy 的时候才用Net2Net 扩张模型。
模型的效果是非常受任务训练顺序影响的。也就是说,会不会发生遗忘,能不能做到知识迁移,和训练任务的先后顺序是有很大关系的。假如说LLL 在未来变得非常热门,那怎么安排机器学习的任务顺序可能会是一个需要讨论的热点问题,这个问题叫做Curriculum Learning 。
http://taskonomy.stanford.edu/#abstract CVPR2018 的best paper
文章目的是找出任务间的先后次序,比如说先做3D-Edges 和 Normals 对 Point Matching 和Reshading 就很有帮助。
在Reinforcement Learning里面会有一个Agent跟一个Environment。
这个Agent会有Observation看到世界种种变化,这个Observation又叫做State,这个State指的是环境的状态,也就是你的machine所看到的东西。我们的state能够观察到一部分的情况,机器没有办法看到环境所有的状态,这个state其实就是Observation。
machine会做一些事情,它做的事情叫做Action,Action会影响环境,会跟环境产生一些互动。因为它对环境造成的一些影响,它会得到Reward,这个Reward告诉它,它的影响是好的还是不好的。
举个例子,比如机器看到一杯水,然后它就take一个action,这个action把水打翻了,Environment就会得到一个negative的reward,告诉它不要这样做,它就得到一个负向的reward。在Reinforcement Learning,这些动作都是连续的,因为水被打翻了,接下来它看到的就是水被打翻的状态,它会take另外一个action,决定把它擦干净,Environment觉得它做得很对,就给它一个正向的reward。机器生来的目标就是要去学习采取哪些action,可以maximize reward
接着,以alpha go为例子,一开始machine的Observation是棋盘,棋盘可以用一个19*19的矩阵来描述,接下来,它要take一个action,这个action就是落子的位置。落子在不同的位置就会引起对手的不同反应,对手下一个子,Agent的Observation就变了。Agent看到另外一个Observation后,就要决定它的action,再take一个action,落子在另外一个位置。用机器下围棋就是这么个回事。在围棋这个case里面,还是一个蛮难的Reinforcement Learning,在多数的时候,你得到的reward都是0,落子下去通常什么事情也没发生这样子。只有在你赢了,得到reward是1,如果输了,得到reward是-1。Reinforcement Learning困难的地方就是有时候你的reward是sparse的,即在只有少数的action 有reward的情况下去挖掘正确的action。
对于machine来说,它要怎么学习下围棋呢,就是找一某个对手一直下下,有时候输有时候赢,它就是调整Observation和action之间的关系,调整model让它得到的reward可以被maximize。
Agent learns to take actions maximizing expected reward.

我们可以比较下下围棋采用Supervised 和Reinforcement 有什么区别。如果是Supervised 你就是告诉机器说看到什么样的盘势就落在指定的位置。
Supervised不足的地方就是:具体盘势下落在哪个地方是最好的,其实人也不知道,因此不太容易做Supervised。机器可以看着棋谱学,但棋谱上面的这个应对不见得是最 optimal的,所以用 Supervised learning 可以学出一个会下围棋的 Agent,但它可能不是真正最厉害的 Agent。
如果是Reinforcement 呢,就是让机器找一个对手不断下下,赢了就获得正的reward,没有人告诉它之前哪几步下法是好的,它要自己去试,去学习。Reinforcement 是从过去的经验去学习,没有老师告诉它什么是好的,什么是不好的,machine要自己想办法知道。
其实在做Reinforcement 这个task里面,machine需要大量的training,可以两个machine互相下。alpha Go 是先做Supervised Learning,做得不错再继续做Reinforcement Learning。
Reinforcement Learning 就是让机器去跟人讲话,讲讲人就生气了,machine就知道一句话可能讲得不太好。不过没人告诉它哪一句话讲得不好,它要自己去发掘这件事情。
这个想法听起来很crazy,但是真正有chat-bot是这样做的,这个怎么做呢?因为你要让machine不断跟人讲话,看到人生气后进行调整,去学怎么跟人对话,这个过程比较漫长,可能得好几百万人对话之后才能学会。这个不太现实,那么怎么办呢,就用Alpha Go的方式,Learning 两个agent,然后让它们互讲的方式。
两个chat-bot互相对话,对话之后有人要告诉它们它们讲得好还是不好。
在围棋里比较简单,输赢是比较明确的,对话的话就比较麻烦,你可以让两个machine进行无数轮互相对话,问题是你不知道它们这聊天聊得好还是不好,这是一个待解决问题。
现有的方式是制定几条规则,如果讲得好就给它positive reward ,讲得不好就给它negative reward,好不好由人主观决定,然后machine就从它的reward中去学说它要怎么讲才是好。后续可能会有人用GAN的方式去学chat-bot。通过discriminator判断是否像人对话,两个agent就会想骗过discriminator,即用discriminator自动learn出给reward的方式。
Reinforcement Learning 有很多应用,尤其是人也不知道怎么做的场景非常适合。
让machine学会做Interactive retrieval,意思就是说有一个搜寻系统,能够跟user进行信息确认的方式,从而搜寻到user所需要的信息。直接返回user所需信息,它会得到一个positive reward,然后每问一个问题,都会得到一个negative reward。
Reinforcement Learning 还有很多应用,比如开个直升机,开个无人车呀,据说最近 DeepMind 用 Reinforcement Learning 的方法来帮 Google 的 server 节电,也有文本生成等。
现在Reinforcement Learning最常用的场景是电玩。现在有现成的environment,比如Gym,Universe。
让machine 用Reinforcement Learning来玩游戏,跟人一样,它看到的东西就是一幅画面,就是pixel,然后看到画面,它要做什么事情它自己决定,并不是写程序告诉它说你看到这个东西要做什么。需要它自己去学出来。
Space invader
游戏的终止条件是所有的外星人被消灭或者你的太空飞船被摧毁。
这个游戏里面,你可以take的actions有三个,可以左右移动跟开火。
machine会看到一个observation,这个observation就是一幕画面。一开始machine看到一个observation ,这个其实就是一个matrix,因为它有颜色,所以是一个三维的pixel。machine看到这个画面以后,就要决定它take什么action,现在只有三个action可以选择。比如它take 往右移。每次machine take一个action以后,它会得到一个reward,这个reward就是左上角的分数。往右移不会得到任何的reward,所以得到的reward ,machine 的action会影响环境,所以machine看到的observation就不一样了。现在observation为,machine自己往右移了,同时外星人也有点变化了,这个跟machine的action是没有关系的,有时候环境会有一些随机变化,跟machine无关。machine看到之后就要决定它要take哪个action,假设它决定要射击并成功的杀了一只外星人,就会得到一个reward,杀不同的外星人,得到的分数是不一样的。假设杀了一只5分的外星人,这个observation就变了,少了一只外星人。
这个过程会一直进行下去,直到某一天在第 T 个回合的时候,machine take action ,然后他得到的 reward 进入了另外一个 state,这个 state 是个 terminal state,它会让游戏结束。可能这个machine往左移,不小心碰到alien的子弹,就死了,游戏就结束了。从这个游戏的开始到结束,就是一个episode,machine要做的事情就是不断的玩这个游戏,学习怎么在一个episode里面怎么去maximize reward,在死之前杀最多的外星人同时要闪避子弹,让自己不会被杀死。
那么Reinforcement Learning的难点在哪里呢?它有两个难点
Reward delay
第一个难点是,reward出现往往会存在delay,比如在space invader里面只有开火才会得到reward,但是如果machine只知道开火以后就会得到reward,最后learn出来的结果就是它只会乱开火。对它来说,往左往右移没有任何reward。事实上,往左往右这些moving,它对开火是否能够得到reward是有关键影响的。虽然这些往左往右的action,本身没有办法让你得到任何reward,但它帮助你在未来得到reward,就像规划未来一样,machine需要有这种远见,要有这种vision,才能玩好。在下围棋里面,有时候也是一样的,短期的牺牲可以换来最好的结果。
Agent's actions affect the subsequent data it receives
Agent采取行动后会影响之后它所看到的东西,所以Agent要学会去探索这个世界。比如说在这个space invader里面,Agent只知道往左往右移,它不知道开火会得到reward,也不会试着击杀最上面的外星人,就不会知道击杀这个东西可以得到很高的reward,所以要让machine去explore它没有做过的行为,这个行为可能会有好的结果也会有坏的结果。但是探索没有做过的行为在Reinforcement Learning里面也是一种重要的行为。
Reinforcement Learning 其实有一个 typical 的讲法,要先讲 Markov Decision Process,在 Reinforcement Learning 里面很红的一个方法叫 Deep Q Network,今天也不讲 Deep Q Network,现在最强的方法叫 A3C,所以我想说不如直接来讲 A3C,直接来讲最新的东西。
Reinforcement Learning 的方法分成两大块,一个是Policy-based的方法,另一个是Valued-based的方法。先有Valued-based的方法,再有Policy-based的方法,所以一般教科书都是讲 Value-based 的方法比较多。
在Policy-based的方法里面,会learn一个负责做事的Actor,在Valued-based的方法会learn一个不做事的Critic。我们要把Actor和Critic加起来叫做Actor+Critic的方法。
现在最强的方法就是Asynchronous Advantage Actor-Critic(A3C)。Alpha Go是各种方法大杂烩,有Policy-based的方法,有Valued-based的方法,有model-based的方法。下面是一些学习deep Reinforcement Learning的资料
先来看看怎么学一个Actor,所谓的Actor是什么呢?我们之前讲过,Machine Learning 就是找一个Function,Reinforcement Learning也是Machine Learning 的一种,所以要做的事情也是找Function。Actor就是一个Function ,这个Function的input就是Machine看到的observation,它的output就是Machine要采取的Action。我们要通过reward来帮我们找这个best Function。

找个这个Function有三个步骤:
第一个步骤就是决定你的Function长什么样子,假设你的Function是一个Neural Network,就是一个deep reinforcement learning。
如果Neural Network作为一个Actor,这个Neural Network的输入就是observation,可以通过一个vector或者一个matrix 来描述。output就是你现在可以采取的action。
举个例子,Neural Network作为一个Actor,inpiut是一张image,output就是你现在有几个可以采取的action,output就有几个dimension。假设我们在玩Space invader,output就是可能采取的action左移、右移和开火,这样output就有三个dimension分别代表了左移、右移和开火。
这个Neural Network怎么决定这个Actor要采取哪个action呢?通常做法是这样,把 image 丢到 Neural Network 里面去,他就会告诉你每一个 output 的 dimension 也就是每一个 action 所对应的分数。你可以采取分数最高的 action,比如说 left 分数最高,假设已经找好这个 Actor,machine 看到这个画面他可能就采取 left。

但是做 Policy Gradient 的时候,通常会假设Policy 是 stochastic,所谓的 stochastic 的意思是你的 Policy 的 output 其实是个机率,如果你的分数是 0.7、0.2 跟 0.1,有 70% 的机率会 left,有 20% 的机率会 right,10% 的机率会 fire,看到同样画面的时候,根据机率,同一个 Actor 会采取不同的 action。这种 stochastic 的做法其实很多时候是会有好处的,比如说要玩猜拳,如果 Actor 是 deterministic,可能就只会一直输,所以有时候会需要 stochastic 这种 Policy。在底下的 lecture 里面都假设 Actor 是 stochastic 的。
用 Neural Network 来当 Actor 有什么好处?传统的作法是直接存一个 table,这个 table 告诉我看到这个 observation 就采取这个 action,看到另外一个 observation 就采取另外一个 action。但这种作法要玩电玩是不行的,因为电玩的 input 是 pixel,要穷举所有可能 pixel 是没有办法做到的,所以一定要用 Neural Network 才能够让 machine 把电玩玩好。用 Neural Network 的好处就是 Neural Network 可以举一反三,就算有些画面完全没有看过,因为 Neural Network 的特性,input 一个东西总是会有 output,就算是他没有看过的东西,他也有可能得到一个合理的结果,用 Neural Network 的好处是他比较 generalize。
第二步骤就是,我们要决定一个Actor的好坏。在Supervised learning中,我们是怎样决定一个Function的好坏呢?假设给一个 Neural Network ,参数假设已经知道就是 ,有一堆 training example,假设在做 image classification,就把 image 丢进去看 output 跟 target 像不像,如果越像的话这个Function就会越好,定义一个东西叫做 Loss,算每一个 example 的 Loss ,合起来就是 Total Loss。需要找一个参数去 minimize 这个 Total Loss。

在Reinforcement Learning里面,一个Actor的好坏的定义是非常类似的。假设我们现在有一个Actor,这个Actor就是一个Neural Network。
Neural Network的参数是,即一个Actor可以表示为,它的input就是Mechine看到的observation。
那怎么知道一个Actor表现得好还是不好呢?我们让这个Actor实际的去玩一个游戏,玩完游戏得到的total reward为 ,把每个时间得到的reward合起来,这就是一个episode里面,你得到的total reward。
这个total reward是我们需要去maximize的对象。我们不需要去maximize 每个step的reward,我们是要maximize 整个游戏玩完之后的total reward。
假设我们拿同一个Actor,每次玩的时候,其实都会不一样的。因为两个原因,首先 Actor 如果是 stochastic ,看到同样的场景也会采取不同的 actio。所以就算是同一个Actor,同一组参数,每次玩的时候你得到的也会不一样的。游戏本身也有随机性,就算你采取同一个Action,你看到的observation每次也可能都不一样。所以是一个Random Variable。我们做的事情,不是去maximize某一次玩游戏时的,而是去maximize 的期望值。这个期望值就衡量了某一个Actor的好坏,好的Actor期望值就应该要比较大。

那么怎么计算呢,我们假设一场游戏就是一个trajectory
包含了state(observation),看到这个 observation 以后take的Action,得到的Reward,是一个sequence。
代表在这个episode里面,最后得到的总reward。
当我们用某一个Actor去玩这个游戏的时候,每个都会有出现的机率,代表从游戏开始到结束过程,这个过程有千百万种。当你选择这个Actor的时候,你可能只会看到某一些过程,某些过程特别容易出现,某些过程比较不容易出现。每个游戏出现的过程,可以用一个机率来表示它,就是说参数是时这个过程出现的机率。
那么的期望值为
实际上要穷举所有的是不可能的,那么要怎么做?让Actor去玩N场这个游戏,获得N个过程 ,玩N场就好像从去Sample N个。假设某个它的机率特别大,就特别容易被sample出来。让Actor去玩N场,相当于从概率场抽取N个过程,可以通过N个Reward的均值进行近似,如下表达
怎么选择最好的function,其实就是用我们的Gradient Ascent。我们已经找到目标了,就是最大化这个
就可以用Gradient Ascent进行最大化,过程为:
参数,那么就是对每个参数的偏微分,如下
实际的计算中
中,只有跟有关系,所以只需要对做Gradient ,即
所以就算不可微也没有关系,或者是不知道它的function也可以,我们只要知道把放进去得到值就可以。
接下来,为了让出现
由于
所以
从而可以通过抽样的方式去近似,即
即拿去玩N次游戏,得到,算出每次的。

接下来的问题是怎么计算,因为
其中是初始状态出现的机率,接下来根据会有某个概率在状态下采取Action ,然后根据会得到某个reward ,并跳到另一个state ,以此类推。其中和跟Actor是无关的,只有跟Actor 有关系。


通过取log,连乘转为连加,即
然后对取Gradient,删除无关项,得到
则
这个式子就告诉我们,当我们在某一次游戏中,在状态下采取得到是正的,我们就希望能够使的概率越大越好。反之,如果是负的,就要调整参数,能够使的机率变小。

注意,某个时间点的是乘上这次游戏的所有reward 而不是这个时间点的reward。假设我们只考虑这个时间点的reward,那么就是说只有fire才能得到reward,其他的action你得到的reward都是0。Machine就只会增加fire的机率,不会增加left或者right的机率。最后Learn出来的Agent它就只会fire。
接着还有一个问题,为什么要取log呢?
那么为什么要除以呢?
假设现在让 machine 去玩 N 次游戏,那某一个 state 在第 13 次、第 15 次、第 17 次、第 33 次的游戏,里面看到了同一个 observation。因为 Actor 其实是 stochastic,所以它有个机率,所以看到同样的 s,不见得采取同样 action,所以假设在第 13 个 trajectory,它采取 action a,在第 17 个它采取 b,在 15 个采取 b,在 33 也采取 b,最后的这个 trajectory 得到的 reward 比较大是 2,另外三次得到的 reward 比较小。
但实际上在做 update 的时候,它会偏好那些出现次数比较多的 action,就算那些 action 并没有真的比较好。
因为是 summation over 所有 sample 到的结果,如果 take action b 这件事情,出现的次数比较多,就算它得到的 reward 没有比较大,machine 把这件事情的机率调高,也可以增加最后这一项的结果,虽然这个 action a 感觉比较好,但是因为它很罕见,所以调高这个 action 的机率,最后也不会对你要 maximize 的对象 Objective 的影响也是比较小的,machine 就会变成不想要 maximize action a 出现的机率,转而 maximize action b 出现的机率。这就是为什么这边需要除掉一个机率,除掉这个机率的好处就是做一个 normalization,如果有某一个 action 它本来出现的机率就比较高,它除掉的值就比较大,让它除掉一个比较大的值,machine 最后在 optimize 的时候,就不会偏好那些机率出现比较高的 action。

还有另外一个问题,假设总是正的,那么会出现什么事情呢?在理想的状态下,这件事情不会构成任何问题。假设有三个action,采取的结果得到的reward都是正的,这个正有大有小,假设和的比较大,的比较小,经过update之后,你还是会让出现的机率变小,出现的机率变大,因为会做normalization。但是实做的时候,我们做的事情是sampling,所以有可能只sample b和c,这样b,c机率都会增加,没有sample到,机率就自动减少,这样就会有问题了。
这样,我们就希望有正有负这样,可以通过将来避免,需要自己设计。如下
这样超过b的时候就把机率增加,小于b的时候就把机率降低,不会造成没被sample到的action机率会减小。

可以把训练过程看成多个分类网络的训练过程,优化目标一致。实作上也一样。



Critic就是Learn一个Neural Network,这个Neural Network不做事。
A critic does not determine the action.Given an actor , it evaluates the how good the actor is.
An actor can be found from a critic. e.g. Q-learning。其实也可以从 Critic 得到一个 Actor,这就是Q-learning。
Critic就是learn一个function,这个function可以告诉你说现在看到某一个observation的时候,这个observation有有多好这样。
这个 Critic 其实有很多种,我们今天介绍 state value function
When using actor 𝜋, the cumulated reward expects to be obtained after seeing observation (state) s.
类似回归问题,训练时需要cumulated reward

同样类似回归问题,训练时只需要让 和 中间差的 reward 接近 ,输出仍然是游戏结束时的reward

另外一种 critic,它可以拿来决定 action,这种 critic 我们叫做 Q function。它的 input 就是一个 state,一个 action,output 是在这个 state 采取了 action a 的话,到游戏结束的时候,会得到多少 accumulated reward

有时候我们会改写这个 Q function,假设你的 a 是可以穷举的,你只要输入一个 state s ,你就可以知道说,所有action的情况下,输出分数是多少。它的妙用是这个样子,你可以用 Q function 找出一个比较好的 actor。这一招就叫做 Q learning。

用 inverse reinforcement learning 的方法去推出 reward function,再用 reinforcement learning 的方法去找出最好的 actor
支持向量机(SVM)有两个特点:SVM=铰链损失(Hinge Loss)+核技巧(Kernel Method)
先回顾一下二元分类的做法,为了方便后续推导,这里定义data的标签为-1和+1
当时,,表示属于第一类别;当时,,表示属于第二类别
原本用,不匹配的样本点个数,来描述loss function,其中表示与相匹配,反之,但这个式子不可微分,无法使用梯度下降法更新参数
因此使用近似的可微分的来表示损失函数

下图中,横坐标为,我们希望横坐标越大越好:
纵坐标是loss,原则上,当横坐标越大的时候,纵坐标loss要越小,横坐标越小,纵坐标loss要越大
在的理想情况下,如果,则loss=0,如果,则loss=1,如下图中加粗的黑线所示,可以看出该曲线是无法微分的,因此我们要另一条近似的曲线来替代该损失函数

下图中的红色曲线代表了square loss的损失函数:

此外蓝线代表sigmoid+square loss的损失函数:
绿线则是代表了sigmoid+cross entropy的损失函数:

为什么cross entropy要比square error要来的有效呢?
我们期望在极端情况下,比如与非常不匹配导致横坐标非常负的时候,loss的梯度要很大,这样才能尽快地通过参数调整回到loss低的地方
对sigmoid+square loss来说,当横坐标非常负的时候,loss的曲线反而是平缓的,此时去调整参数值对最终loss的影响其实并不大,它并不能很快地降低
形象来说就是,“没有回报,不想努力”
而对cross entropy来说,当横坐标非常负的时候,loss的梯度很大,稍微调整参数就可以往loss小的地方走很大一段距离,这对训练是友好的
形象来说就是,“努力可以有回报""
紫线代表了hinge loss的损失函数:
当,损失函数化简为
当,损失函数化简为
总结一下,如果label为1,则当,机器就认为loss为0;如果label为-1,则当,机器就认为loss为0,因此该函数并不需要有一个很大的值

在紫线中,当,则已经实现目标,loss=0;当,表示已经得到了正确答案,但Hinge Loss认为这还不够,它需要你继续往1的地方前进
事实上,Hinge Loss也是Ideal loss的upper bound,但是当横坐标时,它与Ideal loss近乎是完全贴近的
比较Hinge loss和cross entropy,最大的区别在于他们对待已经做得好的样本点的态度,在横坐标的区间上,cross entropy还想要往更大的地方走,而Hinge loss则已经停下来了,就像一个的目标是”还想要更好“,另一个的目标是”及格就好“
在实作上,两者差距并不大,而Hinge loss的优势在于它不怕outlier,训练出来的结果鲁棒性(robust)比较强
在线性的SVM里,我们把看做是向量和向量的内积,也就是新的和,这么做可以把bias项省略掉
在损失函数中,我们通常会加上一个正规项,即
这是一个convex的损失函数,好处在于无论从哪个地方开始做梯度下降,最终得到的结果都会在最低处,曲线中一些折角处等不可微的点可以参考NN中relu、maxout等函数的微分处理

对比Logistic Regression和Linear SVM,两者唯一的区别就是损失函数不同,前者用的是cross entropy,后者用的是Hinge loss
事实上,SVM并不局限于Linear,尽管Linear可以带来很多好的特质,但我们完全可以在一个Deep的神经网络中使用Hinge loss的损失函数,就成为了Deep SVM,其实Deep Learning、SVM这些方法背后的精神都是相通的,并没有那么大的界限
尽管SVM大多不是用梯度下降训练的,但使用该方法训练确实是可行的,推导过程如下:

前面列出的式子可能与你平常看到的SVM不大一样,这里将其做一下简单的转换
对,用 来表示
其中
对、来说,它与上式原本是不同的,因为max是二选一,而则多大都可以
但是当加上取loss function 最小化这个条件时,就要取到等号,两者就是等价的

此时该表达式就和你熟知的SVM一样了:
,且,其中和要同号,要大于等于0,这里的作用就是放宽1的margin,也叫作松弛变量(slack variable)
这是一个QP问题(Quadradic programming problem),可以用对应方法求解,当然前面提到的梯度下降法也可以解
你要先说服你自己一件事:实际上我们找出来的可以minimize损失函数的参数,其实就是data的线性组合
你可以通过拉格朗日乘数法去求解前面的式子来验证,这里试图从梯度下降的角度来解释:
观察的更新过程可知,如果被初始化为0,则每次更新的时候都是加上data point 的线性组合,因此最终得到的依旧会是的Linear Combination
而使用Hinge loss的时候,或者说往往会是0,不是所有的都会被加到里去,而被加到里的那些,才是会决定model和parameter样子的data point,就叫做support vector

SVM解出来的是sparse的,因为有很多的系数微分为0,这意味着即使从数据集中把这些的样本点移除掉,对结果也是没有影响的,这可以增强系统的鲁棒性;而在传统的cross entropy的做法里,每一笔data对结果都会有影响,因此鲁棒性就没有那么好
知道是的线性组合之后,我们就可以对原先的SVM函数进行改写:
这里的表示新的data,表示数据集中已存在的所有data,由于很多为0,因此计算量并不是很大

接下来把与的内积改写成Kernel function的形式:
此时model就变成了,未知的参数变成了
现在我们的目标是,找一组最好的,让loss最小,此时损失函数改写为:
从中可以看出,我们并不需要真的知道的vector是多少,需要知道的只是跟之间的内积值,也就是说,只要知道Kernel function ,就可以去对参数做优化了,这招就叫做Kernel Trick
只要满足是的线性组合,就可以使用Kernel Trick,所以也可以有Kernel based Logistic Regression,Kernel based Linear Regression

linear model会有很多的限制,有时候需要对输入的feature做一些转换之后,才能用linear model来处理,假设现在我们的data是二维的,,先要对它做feature transform,然后再去应用Linear SVM
如果要考虑特征之间的关系,则把特征转换为,此时Kernel function就变为:

可见,我们对和做特征转换+内积,就等同于在原先的空间上先做内积再平方,在高维空间里,这种方式可以有更快的速度和更小的运算量

在Radial Basis Function Kernel中,,如果x和z越像,Kernel的值越大。实际上也可以表示为,只不过的维数是无穷大的,所以我们直接使用Kernel trick计算,其实就等同于在无穷多维的空间中计算两个向量的内积
将Kernel展开成无穷维如下:

把与相关的无穷多项串起来就是,把与相关的无穷多项串起来就是,也就是说,当你使用RBF Kernel的时候,实际上就是在无穷多维的平面上做事情,当然这也意味着很容易过拟合
Sigmoid Kernel:,是哪两个 high dimension vector 做 Inner Product 的结果,自己回去用 Taylor Expansion 展开来看就知道了
如果使用的是Sigmoid Kernel,那model 就可以被看作是只有一层hidden layer的神经网络,其中~可以被看作是neuron的weight,变量乘上这些weight,再通过Hyperbolic Tangent 激活函数,最后全部乘上~做加权和,得到最后的

其中neuron的数目,由support vector的数量决定
既然有了Kernel Trick,其实就可以直接去设计Kernel Function,它代表了投影到高维以后的内积,类似于相似度的概念
我们完全可以不去管和的特征长什么样,因为用低维的和加上,就可以直接得到高维空间中和经过转换后的内积,这样就省去了转换特征这一步
当是一个有结构的对象,比如不同长度的sequence,它们其实不容易被表示成vector,我们不知道的样子,就更不用说了,但是只要知道怎么计算两者之间的相似度,就有机会把这个Similarity当做Kernel来使用
我们随便定义一个Kernel Function,其实并不一定能够拆成两个向量内积的结果,但有Mercer's theory可以帮助你判断当前的function是否可拆分
下图是直接定义语音vector之间的相似度来做Kernel Trick的示例:

Support Vector Regression(SVR)
Ranking SVM
One-class SVM
这里简单比较一下SVM和Deep Learning的差别:
deep learning的前几层layer可以看成是在做feature transform,而后几层layer则是在做linear classifier
SVM也类似,先用Kernel Function把feature transform到高维空间上,然后再使用linear classifier
在SVM里一般Linear Classifier都会采用Hinge Loss

事实上它是 learnable的,但是它没有办法 learn 的像 Deep Learning 那么多。 你可以做的是你有好几个不同的 kernel,然后把不同 kernel combine 起来,他们中间的 weight 是可以 learn 的。当你只有一个 kernel 的时候,SVM 就好像是只有一个 Hidden Layer 的 Neural Network,当你把 kernel 在做 Linear Combination 的时候,他就像一个有两个 layer 的 Neural Network
本文将简单介绍无监督学习中的生成模型,包括PixelRNN、VAE
正如Richard Feynman所说,“What I cannot create, I do not understand”,我无法创造的东西,我也无法真正理解,机器可以做猫狗分类,但却不一定知道“猫”和“狗”的概念,但如果机器能自己画出“猫”来,它或许才真正理解了“猫”这个概念
这里将简要介绍:PixelRNN、VAE和GAN这三种方法
RNN可以处理长度可变的input,它的基本思想是根据过去发生的所有状态去推测下一个状态
PixelRNN的基本思想是每次只画一个pixel,这个pixel是由过去所有已产生的pixel共同决定的
这个方法也适用于语音生成,可以用前面一段的语音去预测接下来生成的语音信号
总之,这种方法的精髓在于根据过去预测未来,画出来的图一般都是比较清晰的
用这个方法去生成宝可梦,有几个tips:
为了减少运算量,将40×40的图像截取成20×20
如果将每个pixel都以[R, G, B]的vector表示的话,生成的图像都是灰蒙蒙的,原因如下:
亮度比较高的图像,一般都是RGB值差距特别大而形成的,如果各个维度的值大小比较接近,则生成的图像偏向于灰色
如果用sigmoid function,最终生成的RGB往往都是在0.5左右,导致色彩度不鲜艳
解决方案:将所有色彩集合成一个1-of-N编码,由于色彩种类比较多,因此这里先对类似的颜色做clustering聚类,最终获得了167种色彩组成的向量
我们用这样的向量去表示每个pixel,可以让生成的色彩比较鲜艳
使用PixelRNN训练好模型之后,给它看没有被放在训练集中的3张图像的一部分,分别遮住原图的50%和75%,得到的原图和预测结果的对比如下:
前面的文章中已经介绍过Autoencoder的基本思想,我们拿出其中的Decoder,给它随机的输入数据,就可以生成对应的图像
但普通的Decoder生成效果并不好,VAE可以得到更好的效果
在VAE中,code不再直接等于Encoder的输出,这里假设目标降维空间为3维,那我们使Encoder分别输出和,此外我们从正态分布中随机取出三个点,将下式作为最终的编码结果:

此时,我们的训练目标不仅要最小化input和output之间的差距,还要同时最小化下式:
与PixelRNN不同的是,VAE画出的图一般都是不太清晰的,但使用VAE可以在某种程度上控制生成的图像
假设我们将这个VAE用在pokemon creation上面。
那我们在train的时候,input一个pokemon,然后你output一个的pokemon,然后learn出来的这个code就设为10维。learn好这个pockmon的VAE以后,我么就把decoder的部分拿出来。因为我们现在有一个decoder,可以input一个vector。所以你在input的时候你可以这样做:我现在有10维的vector,我固定其中8维只选其中的二维出来,在这两维dimension上面散不同的点,然后把每个点丢到decoder里面,看它合出来的image长什么样子。
那如果我们做这件事情的话,你就可以看到说:这个code的每一个dimension分别代表什么意思。如果我们可以解读code每一个dimension代表的意思,那以后我们就可以把code当做拉杆一样可以调整它,就可以产生不同的pokemon。
VAE还可以用来写诗,我们只需要得到某两句话对应的code,然后在降维后的空间中得到这两个code所在点的连线,从中取样,并输入给Decoder,就可以得到类似下图中的效果

VAE和传统的Autoencoder相比,有什么优势呢?
事实上,VAE就是加了噪声noise的Autoencoder,它的抗干扰能力更强,过渡生成能力也更强
对原先的Autoencoder来说,假设我们得到了满月和弦月的code,从两者连线中随机获取一个点并映射回原来的空间,得到的图像很可能是完全不一样的东西。
而对VAE来说,它要保证在降维后的空间中,加了noise的一段范围内的所有点都能够映射到目标图像,如下图所示,当某个点既被要求映射到满月、又被要求映射到弦月,VAE training的时候你要minimize mean square,所以这个位置最后产生的图会是一张介于满月和半月的图。所以你用VAE的话,你从你的code space上面去sample一个code再产生image的时候,你可能会得到一个比较好的image。如果是原来的auto-encoder的话,得到的都不像是真实的image。

再回过来头看VAE的结构,其中:
其实就代表原来的code
则代表加了noise以后的code
代表了noise的variance,描述了noise的大小,这是由NN学习到的参数
注:使用的目的是保证variance是正的
是正态分布中随机采样的点
注意到,损失函数仅仅让input和output差距最小是不够的,因为variance是由机器自己决定的,如果不加以约束,它自然会去让variance=0,这就跟普通的Autoencoder没有区别了
额外加的限制函数解释如下:
下图中,蓝线表示,红线表示,两者相减得到绿线
绿线的最低点,则variance ,此时loss最低
而项则是对code的L2 regularization,让它比较sparse,不容易过拟合,比较不会 learn 出太多 trivial 的 solution

刚才是比较直观的理由,正式的理由这样的,以下是paper上比较常见的说法。

回归到我们要做的事情是什么,你要machine generate 这个pokemon的图,那每一张pokemon的图都可以想成是高维空间中的一个点。一张 image,假设它是 20*20 的 image,它在高维的空间中就是一个 20*20,也就是一个 400 维的点。我们这边写做 x,虽然在图上,我们只用一维来描述它,但它其实是一个高维的空间。那我们现在要做的事情其实就是 estimate 高维空间上面的机率分布,P(x)。只要我们能够 estimate 出这个 P(x) 的样子,注意,这个 x 其实是一个 vector,我们就可以根据这个 P(x),去 sample 出一张图。那找出来的图就会像是宝可梦的样子,因为你取 P(x) 的时候,机率高的地方比较容易被 sample 出来,所以,这个 P(x) 理论上应该是在有宝可梦的图的地方,它的机率是大的;如果是一张怪怪的图的话,机率是低的。如果我们今天能够 estimate 出这一个 probability distribution那就结束了。
那怎么 estimate 一个 probability 的 distribution 呢?

我们可以用 Gaussian mixture model。我们现在有一个 distribution,它长这个样子,黑色的、很复杂。我们说这个很复杂的黑色 distribution,它其实是很多的 Gaussian。这一边蓝色的代表有很多的 Gaussian用不同的 weight 迭合起来的结果。假设你今天 Gaussian 的数目够多,你就可以产生很复杂的 distribution。所以,虽然黑色很复杂,但它背后其实是有很多 Gaussian 迭合起来的结果。根据每一个 Gaussian 的 weight去决定你要从哪一个 Gaussian sample data,然后,再从你选择的那个 Gaussian 里面 sample data。如果你的gaussion数目够多,你就可以产生很复杂的distribution,公式为 。
如果你要从p(x)sample出一个东西的时候,你先要决定你要从哪一个gaussion sample东西,假设现在有100gaussion,你根据每个gaussion的weight去决定你要从哪一个gaussion sample data。所以你要咋样从一个gaussion mixture model smaple data呢?首先你有一个multinomial distribution,你从multinomial distribution里面决定你要sample哪一个gaussion,m代表第几个gaussion,它是一个integer。你决定好你要从哪一个m sample gaussion以后,,你有了m以后就可以找到 (每一个gaussion有自己的 ),根据 就可以sample一个x出来。所以p(x)写为summation over 所有的gaussion的weight乘以sample出x的机率 。
每一个x都是从某一个mixture被sample出来的,这件事情其实就很像是做classification一样。我们每一个所看到的x,它都是来自于某一个分类。但是我们之前有讲过说:把data做cluster是不够的,更好的表示方式是用distributed representation,也就是说每一个x它并不是属于某一个class,而是它有一个vector来描述它的各个不同的特性。所以VAE就是gaussion mixture model的 distributed representation的版本。

首先我们要sample一个z,这个z是从normal distribution 中sample出来的。这个vector z的每一个dimension就代表了某种attribute,如图中所示,假设是z是一维的,实际上 z 可能是一个 10 维的、100 维的 vector。到底有几维,是由你自己决定。接下来你Sample 以后,根据你可以决定 ,你可以决定gaussion的 。刚才在gaussion model里面,你有10个mixture,那你就有10个 ,但是在这个地方,你的z有无穷多的可能,所以你的 也有无穷多的可能。那咋样找到这个 呢?做法是:假设 都来自于一个function,你把z带到产生 的这个function , 代表说:现在如果你的attribute是z的时候,你在x space上面的 是多少。同理 代表说:是多少
其实P(x)是这样产生的:在z这个space上面,每一个点都有可能被sample到,只不过是中间这些点被sample出来的机率比较大。当你sample出来点以后,这个point会对应到一个guassion。至于一个点对应到什么样的gaussion,它的 是多少,是由某一个function来决定的。所以当gaussion是从normal distribution所产生的时候,就等于你有无穷多个gaussion。
另外一个问题就是:我们怎么知道每一个应该对应到什么样的 (这个function如何去找)。我们知道neural network就是一个function,所以你就可以说:我就是在train一个neural network,这个neural network的input就是,它的output就是两个vector( )。
P(x)的distribution为
那你可能会困惑,为什么是gaussion呢?你可以假设任何形状的,这是你自己决定的。你可以说每一个attribute的分布就是gaussion,因为极端的case总是少的,比较没有特色的东西总是比较多的。你不用担心如果假设gaussion会不会对P(x)带来很大的限制:NN是非常powerful的,NN可以represent任何的function。所以就算你的z是normal distribution,最后的P(x)最后也可以是很复杂的distribution。
p(z) is a normal distribution, 表示我们先知道 z 是什么,然后我们就可以决定 x 是从什么样子的 mean 跟 variance 的 Gaussian里面被 sample 出来的, 是等待被找出来的。
但是,问题是要怎么找呢?它的criterion就是maximizing the likelihood,我们现在手上已经有一笔data x,你希望找到一组 的function和 的function,它可以让你现在已经有的image x,它的p(x)取log之后相加被maximize 。 通过一个产生这个 跟 ,所以我们要做的事情就是,调整里面的参数(每个neural的weight bias),使得likehood可以被maximize 。
引入另外一个distribution,叫做 。也就是我们有另外一个 ,input一个以后,它会告诉你说:对应在这个space上面的 (给它以后,它会决定这个要从什么样的 被sample出来)。这个就是VAE里的Encoder,前面说的 就是Decoder

,对任何distribution都成立。因为这个积分是跟P(x)无关的,然后就可以提出来,积分的部分就会变成1,所以左式就等于右式。
由条件概率,得到第二行。log中的式子拆开,得到第三行。右边这一项,它代表了一个 KL divergence。KL divergence 代表的是这两个 distribution 相近的程度,如果 KL divergence 它越大代表这两个 distribution 越不像,这两个 distribution 一模一样的时候,KL divergence 会是 0。所以,KL divergence 它是一个距离的概念,它衡量了两个 distribution 之间的距离。最小为0。左边一项经过变化,得到L的lower bound 。

我们要maximize的对象是由这两项加起来的结果,在 这个式子中,是已知的,我们不知道的是 跟 。我们本来要做的事情是要找 ,让likelihood越大越好,现在我们要做的事情变成要找找 跟 ,让 越大越好。
如果我们只找 ,然后去maximizing 的话,那因为你要找的这个 likelihood,它是 的 upper bound,所以,你增加 的时候,你有可能会增加你的 likelihood。但是,你不知道你的这个 likelihood跟你的 lower bound 之间到底有什么样的距离。你希望做到的事情是当你的 lower bound 上升的时候,你的 likelihood 是会比 lower bound 高,然后你的 likelihood 也跟着上升。但是,你有可能会遇到一个比较糟糕的状况是你的 lower bound 上升的时候,likelihood 反而下降。虽然,它还是 lower bound,它还是比 lower bound 大,但是,它有可能下降。因为根本不知道它们之间的差距是多少。
所以,引入 q 这一项呢,其实可以解决刚才说的那一个问题。因为likelihood = + KL divergence。如果你今天去这个调,去 maximize 的话,会发生什么事呢?首先 q 这一项跟 log P(x) 是一点关系都没有的,log P(x) 只跟 有关,所以,这个值是不变的,蓝色这一条长度都是一样的。我们现在去 maximize ,maximize 代表说你 minimize 了 KL divergence,也就是说你会让你的 lower bound 跟你的这个 likelihood越来越接近,假如你固定住 这一项,然后一直去调 这一项的话,让这个 一直上升,最后这一个 KL divergence 会完全不见。
假如你最后可以找到一个 q,它跟这个 正好完全 distribution 一模一样的话,你就会发现说你的 likelihood 就会跟lower bound 完全停在一起,它们就完全是一样大。这个时候呢,如果你再把 lower bound 上升的话,因为你的 likelihood 一定要比 lower bound大。所以这个时候你的 likelihood你就可以确定它一定会上升。所以,这个就是引入 q 这一项它有趣的地方。
一个副产物,当你在 maximize q 这一项的时候,你会让这个 KL divergence 越来越小,你会让这个 跟 越来越接近。
所以我们接下要做的事情就是找 and ,可以让 越大越好。让 越大越好就等同于我们可以让 likelihood 越来越大,而且你顺便会找到 可以去 approximation of

对于 log 里面相乘,拆开,得到 跟 的 KL divergence

q是一个 neural network,当你给 x 的时候,它会告诉你 是从什么样的mean 跟 variance 的 Gaussian 里面 sample 出来的。所以,我们现在如果你要minimize 这个 跟 的 KL divergence 的话,你就是去调output让它产生的 distribution 可以跟这个 normal distribution 越接近越好。minimize这一项其实就是我们刚才在reconstruction error外加的那一项,它要做的事情就是minimize KL divergence,希望 的output跟normal distribution是接近的。

另外一项是要这个积分的意思就是
你可以想象,我们有一个 ,然后,它用 来做 weighted sum。所以,你可以把它写成 根据 的期望值
这个式子的意思就好像是说:给我们一个 的时候,我们去根据这个 ,这个机率分布去 sample 一个 data,然后,要让 的机率越大越好。那这一件事情其实就 Auto-encoder 在做的事情。
怎么从 去 sample 一个 data 呢?你就把 丢到 neural network 里面去,它产生一个 mean 跟一个 variance,根据这个 mean 跟 variance,你就可以 sample 出一个 。
你已经根据现在的 x sample 出 一个 z,接下来,你要 maximize 这一个 z,产生这个 x 的机率。
这个 z 产生这个 x ,是把这个 z 丢到另外一个 neural network 里面去,它产生一个 mean 跟 variance,要怎么让这个 NN output所代表 distribution 产生 x 的 机率越大越好呢?假设我们无视 variance 这一件事情的话,因为在一般实作里面你可能不会把 variance 这一件事情考虑进去。你只考虑 mean 这一项的话,那你要做的事情就是:让这个 mean跟你的 x 越接近越好。你现在是一个 Gaussian distribution,那 Gaussian distribution 在 mean 的地方机率是最高的。所以,如果你让这个 NN output 的这个 mean 正好等于你现在这个 data x 的话,这一项 它的值是最大的。
所以,现在这整个 case 就变成说,input 一个 x,然后,产生两个 vector,然后 sample 产生一个 z,再根据这个 z,你要产生另外一个 vector,这个 vector 要跟原来的 x 越接近越好。这件事情其实就是Auto-encoder 在做的事情。所以这两项合起来就是刚才我们前面看到的 VAE 的 loss function。
VAE其实有一个很严重的问题就是:它从来没有真正学过如何产生一张看起来像真的image,它学到的东西是:它想要产生一张image,跟我们在database里面某张image越接近越好。
但它不知道的是:我们evaluate它产生的image跟database里面的相似度的时候(MSE等等),decoder output跟真正的image之间有一个pixel的差距,不同的pixel落在不同的位置会得到非常不一样的结果。假设这个不一样的pixel落在7的尾部(让7比较长一点),跟落在另外一个地方(右边)。你一眼就看出说:右边这是怪怪的digit,左边这个搞不好是真的。但是对VAE来说都是一个pixel的差异,对它来说这两张image是一样的好或者是一样的不好。
所以VAE学的只是怎么产生一张image跟database里面的一模一样,从来没有想过:要真的产生可以一张以假乱真的image。所以你用VAE来做training的时候,其实你产生出来的image往往都是database里面的image linear combination而已。因为它从来都没有想过要产生一张新的image,它唯一做的事情就是希望它产生的 image 跟 data base 的某张 image 越像越好,模仿而已。
GAN,对抗生成网络,是近两年非常流行的神经网络,基本思想就像是天敌之间相互竞争,相互进步
GAN由生成器(Generator)和判别器(Discriminator)组成:
GANs are difficult to optimize.
No explicit signal about how good the generator is
When discriminator fails, it does not guarantee that generator generates realistic images
Making discriminator more robust may be helpful.
GAN的问题:没有明确的训练目标,很难调整生成器和判别器的参数使之始终处于势均力敌的状态,当两者之间的loss很小的时候,并不意味着训练结果是好的,有可能它们两个一起走向了一个坏的极端,所以在训练的同时还要有人在旁边关注着训练的情况
Ensemble的方法就是一种团队合作,好几个模型一起上的方法。
第一步:通常情况是有很多的classifier,想把他们集合在一起发挥更强大的功能,这些classifier一般是diverse的,这些classifier有不同的属性和不同的作用。就像moba游戏中每个人都有自己需要做的工作。
第二步:就是要把classifier用比较好的方法集合在一起,就好像打团的时候输出和肉都站不同的位置。通常用ensemble可以让我们的表现提升一个档次,在kaggle之类的比赛中,你有一个好的模型,你可以拿到前几名,但你要夺得冠军你通常会需要 ensemble。

我们先来回顾一下bias和variance,对于简单的模型,我们会有比较大的bias但是有比较小的variance,如果是复杂的模型,则有比较小的bias但是有比较大的variance。在这两者的组合下,我们最后的误差(蓝色的线)会随着模型复杂度的增加,先下降后逐渐上升。
如果一个复杂的模型就会有很大的variance。这些模型的variance虽然很大,但是bias是比较小的,所以我们可以把不同的模型都集合起来,把输出做一个平均,得到一个新的模型,这个结果可能和正确的答案就是接近的。Bagging就是要体现这个思想。
Bagging就是我们自己创造出不同的dataset,再用不同的dataset去训练一个复杂的模型,每个模型独自拿出来虽然方差很大,但是把不同的方差大的模型集合起来,整个的方差就不会那么大,而且偏差也会很小。
怎么自己制造不同的 data 呢?假设现在有 N 笔 Training Data,对这 N 笔 Training Data 做 Sampling,从这 N 笔 Training Data 里面每次取 N' 笔 data组成一个新的 Data Set。通常在做 Sampling 的时候会做 replacement,抽出一笔 data 以后会再把它放到 pool 里面去,那所以通常 N' 可以设成 N。所以把 N' 设成 N,从 N 这个 Data Set 里面做 N 次的 Sample with replacement,得到的 Data Set 跟原来的这 N 笔 data 并不会一样,因为你可能会反复抽到同一个 example。总之我们就用 sample 的方法建出好几个 Data Set。每一个 Data Set 都有 N' 笔 Data,每一个 Data Set 里面的 Data 都是不一样的。
接下来你再用一个复杂的模型去对这四个 Data Set 做 Learning,就找出了四个 function。接下来在 testing 的时候,就把一笔 testing data 丢到这四个 function 里面,再把得出来的结果作平均或者是作 Voting。通常就会比只有一个 function 的时候performance 还要好,Variance 会比较小,所以你得到的结果会是比较 robust 的,比较不容易 Overfitting。
如果做的是 regression 方法的时候,你可能会用 average 的方法来把四个不同 function 的结果组合起来,如果是分类问题的话可能会用 Voting 的方法把四个结果组合起来。
注意一下,当你的 model 很复杂的时候、担心它 Overfitting 的时候才做 Bagging。做 Bagging 的目的是为了要减低 Variance,你的 model Bias 已经很小但 Variance 很大,想要减低 Variance 的时候,你才做 Bagging。
所以适用做 Bagging 的情况是,你的 Model 本身已经很复杂,在 Training Data 上很容易就 Overfit,这个时候你会想要用 Bagging。举例来说 Decision Tree就是一个非常容易 Overfit 的方法。所以 Decision Tree 很需要做 Bagging。Random Forest 就是 Decision Tree 做 Bagging 的版本。

假设给定的每个Object有两个feature,我们就用这个training data建立一颗树,如果小于0.5就是yes(往左边走),当大于0.5就是no(往右边走),接下来看,当小于0.3时就是class1(对应坐标轴图中左下角的蓝色)当大于0.3时候就是class2(红色);对右边的当小于0.7时就是红色,当大于0.7就是蓝色。这是一个比较简单的例子,其实可以同时考虑多个dimension,变得更复杂。
做决策树时会有很多地方需要注意:比如每个节点分支的数量,用什么样的criterion 来进行分支,什么时候停止分支,有那些可以问的问题等等,也是有很多参数要调。
描述:输入的特征是二维的,红色的部分是class1,蓝色的部分是class2,其中class1分布的和初音的样子是一样的。我们用决策树对这个问题进行分类。

上图可以看到,深度是5的时候效果并不好,图中白色的就是class1,黑色的是class2.当深度是10的时候有一点初音的样子,当深度是15的时候,基本初音的轮廓就出来了,但是一些细节还是很奇怪(比如一些凸起来的边角)当深度是20的时候,就可以完美的把class1和class2的位置区别开来,就可以完美地把初音的样子勾勒出来了。对于决策树,理想的状况下可以达到错误是0的时候,最极端的就是每一笔data point就是很深的树的一个节点,这样正确率就可以达到100%(树够深,决策树可以做出任何的function)但是决策树很容易过拟合,如果只用决策树一般很难达到好的结果。

传统的随机森林是通过之前的重采样的方法做,但是得到的结果是每棵树都差不多(效果并不好)。比较typical 的方法是在每一次要产生 Decision Tree 的 branch 要做 split 的时候,都 random 的决定哪一些 feature 或哪一些问题是不能用。这样就能保证就算用同样的dataset,每次产生的决策树也会是不一样的,最后把所有的决策树的结果都集合起来,就会得到随机森林。
如果是用Bagging的方法的话,用out-of-bag可以做验证。用这个方法可以不用把label data划分成training set和validation set,一样能得到同样的效果。
具体做法:假设我们有training data是,,,,我们只用第一笔和第二笔data训练(圆圈表示训练,叉表示没训练),我们只用第三笔第四笔data训练,用第一,第三笔data训练,表示用第二,第四笔data训练,我们知道,在训练和的时候没用用到,所以我们就可以用和Bagging的结果在上面测试他们的表现,同理,我们可以用和Bagging的结果来测试,用 跟 Bagging 的结果 test ,用 跟 Bagging 的结果 test 。
接下来再把 跟 的结果把它做平均,算一下 error rate 就得到 Out-of-bag 的 error。虽然我们没有明确的切出一个验证集,但是我们做测试的时候所有的模型并没有看过那些测试的数据。所有这个输出的error也是可以作为反映测试集结果的估测效果。
接下来是用随机森林做的实验结果:

强调一点是做Bagging并不会使模型能更fit data,所以用深度为5的时候还是不能fit出那个function,就是5颗树的一个平均,相当于得到一个比较平滑的树。当深度是10的时候,大致的形状能看出来了,当15的时候效果就还不错,但是细节没那么好,当20 的时候就可以完美的把初音分出来。

Boosting是用在很弱的模型上的,当我们有很弱的模型的时候,不能fit我们的data的时候,我们就可以用Boosting的方法。
Boosting有一个很强的guarantee :假设有一个 ML 的 algorithm,它可以给你一个错误率高过 50% 的 classifier,只要能够做到这件事,Boosting 这个方法可以保证最后把这些错误率仅略高于 50% 的 classifier 组合起来以后,它可以让错误率达到 0%。
Boosting的结构:
要注意的是在做 Boosting 的时候,classifier 的训练是有顺序的(sequential),要先找 才知道怎么找跟 互补的 ,所以它是有顺序的找。在 Bagging 的时候,每一个 classifier 是没有顺序的

制造不同的训练数据来得到不同的分类器
用重采样的方法来训练数据得到新的数据集;用重新赋权重的的方法来训练数据得到新的数据集。
上图中用u来代表每一笔data的权重,可以通过改变weight来制造不同的data,举例来说就是刚开始都是1,第二次就分别改成0.4,2.1,0.7,这样就制造出新的data set。在实际中,就算改变权重,对训练没有太大影响。在训练时,原来的loss function是,其中可以是任何不同的function,只要能衡量和之间的差距就行,然后用gradient descent 的方法来最小化这个L(total loss function)。当加上权重后,变成了,相当于就是在原来的基础上乘以。这样从loss function来看,如果有一笔data的权重比较重,那么在训练的时候就会被多考虑一点。

想法:先训练好一个分类器,要找一组新的training data,让在这组data上的表现很差,然后让在这组training data上训练。
怎么找一个新的训练数据集让表现差?
上图中的就是训练数据的error rate,这个就是对所有训练的样本求和,是计算每笔的training sample分类正确与否,用0来表示正确,用1来表示错误,乘以一个weight ,然后做normalization,这个对所有的weight标准化,这里的
然后我们想要用作为权重的数据来进行计算得到error rate,在新的权重上,的表现就是随机的,恰好等于0.5,接下来我们拿这组新的训练数据集再去训练,这样的和就是互补的。

假设我们上面的四组训练数据,权重就是到,并且每个初始值都是1,我们现在用这四组训练数据去训练一个模型,假设只分类正确其中的三笔训练数据,所以 然后我们改变每个权重,把对的权重改小一点,把第二笔错误的权重改大一点,在新的训练数据集上表现就会变差。 然后在得到的新的训练数据集上训练得到,这个训练完之后得到的会比0.5小。

假设训练数据会被分类错,那么就把第n笔data的乘上变成,这个是大于1的值
如果正确的被分类的话,那么就用除以变成
就会在新的权重上进行训练。

分类错误的对应的就乘上;就等于,也等于分类错误和分类正确的两个的权重和。所以结合一下然后再取个倒数就可以得到图中最后一个式子。

最后得到的结果是,然后用这个去乘或者除权重,就能得到让表现不好的新的训练数据集。由于小于0.5,所以大于1

给定一笔训练数据以及其权重,设置初始的权重为1,接下来用不同的权重来进行很多次迭代训练弱分类器,然后再把这些弱的分类器集合起来就变成一个强的分类器。
其中在每次迭代中,每一笔训练数据都有其对应的权重,用每个弱分类器对应的权重训练出每个弱分类器,计算在各自对应权重中的错误率。
然后就可以重新给训练数据赋权值,如果分类错误的数据,就用原来的乘上来更新其权重,反之就把原来的除以得到一组新的权重,然后就继续在下一次迭代中继续重复操作。(其中)
或者对我们还可以用来代替,这样我们就可以直接统一用乘的形式来更新,变成了乘以或者乘以,这里用来取正负号(当分类错误该式子就是正的,分类正确该式子就是负的),这样表达式子就会更加简便。

经过刚才的训练之后我们就得到了到,一般有两种方法进行集合:
Uniform weight:我们把T个分类器加起来,看其结果是正的还是负的(正的就代表class1,负的就代表class2),这样可以但不是最好的,因为分类器中有好有坏,如果每个分类器的权重都一样的,显然是不合理的。
Non-uniform weight:在每个分类器前都乘上一个权重,然后全部加起来后取结果的正负号,这种方法就能得到比较好的结果。
这里的,从后面的例子可以看到,错误率比较低的=0.1得到最后的=1.10就比较大;反之,如果错误率比较高的=0.4得到最后的=0.20就比较小。错误率比较小的分类器,最后在最终结果的投票上会有比较大的权重。

Decision stump:假设所有的特征都分布在二维平面上,在二维平面上选一个维度切一刀,其中一边为class1,另外一边当做class2。
上图中t=1时,我们先用decision stump找一个,左边就是正类,右边就是负类,其中会发现有三笔data是错误的,所以能得到错误率是0.3,=1.53(训练数据更新的权重),=0.42(在最终结果投票的权重),然后改变每笔训练数据的权重。
t=2和t=3按照同样的步骤,就可以得到第二和第三个分类器。由于设置了三次迭代,这样训练就结束了,用之前每个分类器乘以对应的权重,就可以得到最终分类器。
这个三个分类器把平面分割成六个部分,左上角三个分类器都是蓝色的,那就肯定就蓝色的。
上面中间部分第一个分类器是红色的,第二个第三个是蓝色的,但是后面两个加起来的权重比第一个大,所以最终中间那块是蓝色的。
对于右边部分,第一个第二个分类器合起来的权重比第三个蓝色的权重大,所以就是红色的。
下面部分也是按照同样道理,分别得到蓝色,红色和红色。
所以这三个弱分类器其实都会犯错,但是我们把这三个整合起来就能达到100%的正确率了。
上式中的是最终分类结果的表达式,是权重,是错误率。
Proof: As we have more and more (T increases), achieves smaller and smaller error rate on training data.

先计算总的训练数据集的错误率,也就是其中得到的就是1,反之如果就是0。
进一步,可以把写成,如果是同号的代表是正确的,如果是异号就代表分类错误的。整个错误率有一个upper bound就是
上图中横轴是,绿色的线代表的是的函数,蓝色的是也就是绿色函数的上限。
我们要证明upper bound会越来越小

上式证明中,思路是先求出(也就是第T+1次训练数据集权重的和),就等于,而与有关系,通过的式子,能得到就是T次连乘的,也就是,然后在累加起来得到。
同时把累乘放到exp里面去变成了累加,由于是迭代中第n笔的正确答案,所以和累乘符号没有关系,就会发现后面的恰好等于图片最上面的。
这样就说明了,训练数据的权重的和会和训练数据的错误率有关系。接下来就是证明权重的和会越来越小就可以了。

的权重就是每一笔初试权重的和N,然后这里的就是要根据来求出;对于分类正确的,用乘以乘以,对于分类错误的就乘以再乘以。
然后再把代入到这个式子中化简得到得到
其中,是错误率,肯定小于0.5,所以当时,最大值为1,所以小于等于。
就是N乘以T个连乘。
这样的一来训练数据的错误率的upper bound就会越来越小。

其中图中x轴是训练的次数,y轴是错误大小,从这张图我们发现训练数据集上的错误率其实很快就变成了0,但是在 testing data 上的 error 仍然可以继续下降。
我们把定义为margin,我们希望它们是同号,同时不只希望它同号,希望它相乘以后越大越好
原因:图中是5,100,1000个权重的分类器结合在一起时margin的分布图,当5个分类器结合的时候,其实margin已经大于0了,但是当增加弱分类器的数量的时候,margin还会一直变大,增加 margin 的好处是让你的方法比较 robust,可以在 testing set 上得到比较好的 performance。
为什么margin会增加?

该图是的函数图像,红色的线就是AdaBoost的目标函数,从图中可以看出AdaBoost的在为时,error 并不是 0,它可以把再更往右边推然后得到更小的 error,依然能不断的下降,也就是让(margin)能不断增大,得到更小的错误。
Logistic Regression和SVM也可以做到同样的效果。

本来深度是5的决策树是不能做好初音的分类(只能通过增加深度来进行改进),但是现在有了AdaBoost的决策树是互补的,所以用AdaBoost就可以很好的进行分类。T代表AdaBoost运行次数,图中可知用AdaBoost,100棵树就可以很好的对初音进行分类。

Gradient Boosting是Boosting的更泛化的一个版本。 具体步骤:
初始化一个,
现在进行很多次的迭代,找到一组和来共同改进
经过T次迭代,得到的
这里的cost function是,其中用来衡量和的差异(比如说可以用 Cross Entropy 或 Mean Square Error 等等)这里定义成了。
接下来我们要最小化损失函数,我们就需要用梯度下降来更新每个

从梯度下降角度考虑:上图式子中,我们需要用函数对求梯度,然后用这个得到的梯度去更新,得到新的 这里对求梯度的函数就是可以想成每一点就是一个参数,那其实 就是一个 vector ,通过调整参数就能改变函数的形状,这样就可以对做偏微分。
从Boosting角度考虑,红色框的两部分应该是同方向的,如果和其方向是一致的话,那么就可以把加上,就可以让新的损失减少。
我们希望和方向越一致越好。所以我们希望maximize两个式子相乘,保证这两个式子方向一致。
对于得到的新式子,可以想成对每一笔 training data 都希望跟他们是同号的,然后每一笔 training data 前面都乘上了一个 weight ,经过计算之后发现这个权重恰好就是AdaBoost上的权重。

这里找出来的,其实也就是AdaBoost找出来的,所以在AdaBoost的时候,找一个弱的分类器的时候,就相当于用梯度下降更新损失,值得损失会变小。

Gradient Boosting 里面, 是一个 classifier,在找 的过程中运算量可能就是很大的,甚至如果 ft 是个 Neural Network,要把 找出来的时候本身就需要很多次的 Gradient Descent 的 iteration。由于求是很不容易才找到的,所以我们这里就会给配一个最好的,把的价值发挥到最大。
有点像学习率,但是这里我们固定,穷举所有的,找到一个使得的损失更小。
实际中不可能穷举,就是求解一个optimization 的 problem,找出一个,让最小,这里用计算偏微分的方法求极值。巧合的是找出来的就是。
所以 Adaboost 整件事情,就可以想成它也是在做 Gradient Descent。只是 Gradient 是一个 function。
Gradient Boosting 有一个好的地方是,可以任意更改 Objective Function。
为了让 performance 再提升,就要把四个人的 model combine 起来,把一笔数据x输入到四个不同的模型中,然后每个模型输出一个y,然后用Majority Vote决定出最好的(对于分类问题)。
但是有个问题就是并不是所有系统都是好的,有些系统会比较差,但是如果采用之前的设置低权重的方法又会伤害小毛的自尊心,这样我们就提出一种方法:

把得到的system 的 output 当做feature输入到一个classifier 中,然后再决定最终的结果。
这个最终的 classifier 就不需要太复杂,最前面如果都已经用好几个 Hidden Layer 的 Neural Network 了,也许 final classifier 就不需要再好几个 Hidden Layer 的 Neural Network,它可以只是 Logistic Regression 就行了。
那在做这个实验的时候要注意,我们会把有 label 的 data 分成 training set 跟 validation set。在做 Stacking 的时候要把 training set 再分成两部分,一部分的 training set 拿来 learn 这些 classifier,另外一部分的 training data 拿来 learn 这个 final classifier。
有的要来做 Stacking 的前面 classifier,它可能只是 fit training data的overfit model。如果 final classifier 的 training data跟这些 system 用的 training data 是同一组的话,就会因为这个model在training set上正确率很高而给其很高的权重。所以在 train final classifier 的时候必须要用另外一笔 training data 来 train final classifier,不能跟前面 train system的 classifier 一样。
什么是Structured Learning呢? 到目前为止,我们考虑的input都是一个vector,output也是一个vector,不管是SVM还是 Deep Learning的时候,我们的input,output都是vector而已。但是实际上我们要真正面对的问题往往比这个更困难,我们可能需要input或者output是一个sequence,我们可能希望output是一个list,是一个tree,是一个bounding box等等。比如recommendation里面你希望output是一个list,而不是一个个element。
当然,大原则上我们知道怎么做,我们就是要找一个function,它的input就是我们要的object,它的output就是另外一种object,只是我们不知道要怎么做。比如说,我们目前学过的deep learning的Neural Network的架构,你可能不知道怎样Network的input才是一个tree structure,output是另外一个tree structure。

特点:
Structured Learning 的应用比比皆是
Speech recognitian(语音辨识)
input 是一个signal sequence,output是另一个text sequence
Translation(翻译)
input 是一种语言的sequence,output是另外一种语言的sequence
Syntatic Paring(文法解析)
input 是一个sentence,output 是一个文法解析树
Object Detection(目标检测)
或者你要做Object detection,input 是一张image,output是一个bounding box。你会用这个bounding box把这个object给框出来。
Summarization
或者你要做一个Summarization,input是一个大的document,output是一个summary。input 和output都是一个sequence。
Retrieval
或者你要做一个Retrieval,input是搜寻的关键词,output是搜寻的结果,是一个webpage的list。
那么Structured到底要怎么做呢?虽然这个Structured听起来很困难,但是实际上它有一个Unified Framework,统一的框架。
在Training的时候,就是找到function,记为,这个大写的input是跟,它的output是一个real number。这个大写的它所要做的事情就是衡量出输入x,输出y都是structure的时候,x和y有多匹配。越匹配,R值越大。

那testing的时候,给定一个新的x,我们去穷举所有的可能的y,一一带进大写的 function,看哪一个y可以让函数值最大,此时的就是最后的结果,model的output。
之前我们所要做的事情,是找一个小写的,可以想象成现在小写的,这样讲可能比较抽象,我们来举个实际的例子。
用一个方框标识出一张图片中的要它找的object,在我们的task中input是一张image,output是一个Bounding Box。举例来说,我们的目标是要检测出Haruhi。input是一张image,output就是Haruhi所在的位置。可以用于侦测人脸,无人驾驶等等。
在做object detection的时候,也可以用Deep Learning。事实上,Deep Learning 和Structured Learning是有关系的,这个是我个人的想法,GAN就是F(X,Y),具体的后续再讲。
那么Object Detection是怎么做的呢?input就是一张image,output就是一个Bounding Box,F(x,y)就是这张image配上这个红色的bounding box,它们有多匹配。如果是按照Object Detection的例子,就是它有多正确,真的吧Harihu给框出来。所以你会期待,给这一张图,如果框得很对,那么它的分数就会很高。如下图右侧所示。

接下来,testing的时候,给一张image,这个x是从来没有看过的东西。你穷举所有可能的bounding box,画在各种不同的地方,然后看说哪一个bounding box得到的分数最高。红色的最高,所以红色的就是你的model output。

在别的task上其实也是差不多的,比如
input 一个长document,里面有很多句子。output是一个summary,summary可以从document上取几个句子出来。
那么我们training的时候,你的这个F(x,y),当document和summary配成一对的时候,F的值就很大,如果document和不正确的summary配成一对的时候,F的值就很小,对每一个training data 都这么做。
testing的时候,就穷举所有可能的summary,看哪个summary配上的值最大,它就是model的output。

input 是一个查询集(查询关键字),output是一个webpages的list
Training的时候,我们要知道input一个query时,output是哪一些list,才是perfect。以及那些output是不对的,分数就会很低。
Testing的时候,根据input,穷举所有的可能,看看哪个list的分数最高,就是model的输出。
这个Unified Framework或许你听得觉得很怪这样,第一次听到,搞什么东西呀。
那么我换一个说法,我们在Training的时候要estimate x和y的联合概率P(x,y),即x和y一起出现的机率,这样,input就是X和Y,output就是一个介于0到1之间的值。
那我在做testing的时候,给我一个object x,我去计算所有的,经过条件概率的推导,哪一个的机率最高,就是model的输出。

graphical model也是一种structured learning,就是把换成机率
用机率表达的方式
缺点
优点
Energy-based model 也是structured learning
要做这个Framework要解三个问题
第一个问题是,在不同的问题中,F(x,y)到底应该是什么样的。

再来就是那个荒唐的Inference,怎么解 “arg max”这个问题。这个Y可是很大的,比如说你要做Object Detection,这个Y是所有可能的bounding box。这件事情做得到吗?

第三个问题是Training,给定training data ,如何找到。Training Principle是正确的能大过其他的情况,这个Training 应该是可以完成的。

只要你解出这三个问题,你就可以做Structured Learning。

这三个问题可以跟HMM的三个问题联系到一起,也可以跟DNN联系到一起。
怎么说呢,比如说我们现在要做手写数字辨识,input一个image,把它分成10类,先把x扔进一个DNN,得到一个N(x),接下来我再input y,y是一个vector,把这个y和N(x)算cross entropy, 就是。

接下来,在testing的时候,就是说,我穷所有可能的辨识结果,也就是说10个y,每个都带进去这个Function里面,看哪个辨识结果能够让最大,它就是我的辨识结果。这个跟我们之前讲的知识是一模一样的。
假如Problem 1中的F(x,y)有一种特殊的形式,那么Problem 3就不是个问题。所以我们就要先来讲special form应该长什么样子。
Evaluation: What does F(x,y) look like?
special form必须是Linear,也就是说一个(x,y)的pair,首先我用一组特征来描述(x,y)的pair,其中代表一种特征,也就说(x,y)具有特征是这个值,具有特征是这个值,等等。然后F(x,y)它长得什么样子呢?
向量形式可以写为

举个object detection的例子,框出Harihu,函数可能为红色的pixel在框框里出现的百分比为一个维度,绿色的pixel在框框里出现的百分比为一个维度,蓝色的是一个维度,或者是红色在框框外的百分比是一个维度,等等,或者是框框的大小是一个维度。
现在image中比较state-of-the-art 可能是用visual word,visual word就是图片上的小方框片,每一个方片代表一种pattern,不同颜色代表不同的pattern,就像文章词汇一样。你就可以说在这个框框里面,编号为多少的visual word出现多少个就是一个维度的feature。
这些feature要由人找出来的吗?还是我们直接用一个model来抽呢,F(x,y)是一个linear function,它的能力有限,没有办法做太厉害的事情。如果你想让它最后performance好的话,那么就需要抽出很好的feature。用人工抽取的话,不见得能找出好的feature。
所以如果是在object detection 这个task上面,state-of-the-art 方法,比如你去train一个CNN,你可以把image丢进CNN,然后output一个vector,这个vector能够很好的代表feature信息。现在google在做object detection 的时候其实是用deep network 加上 structured learning 的方法做的,抽feature是用deep learning的方式来做,具体如下图

你的x是一个document,y是一个paragraph。你可以定一些feature,比如说表示y里面包含“important”这个单词则为1,反之为0,包含的话y可能权重会比较大,可能是一个合理的summarization,或者是,y里面有没有包含“definition”这个单词,或者是,y的长度,或者你可以定义一个evaluation说y的精简程度等等,也可以想办法用deep learning找比较有意义的表示。具体如下图

那比如说是Retrieval,其实也是一样啦。x是keyword,y是搜寻的结果。比如表示y第一笔搜寻结果跟x的相关度,或者表示y的第一笔搜寻结果有没有比第二笔高等等,或者y的Diversity的程度是多少,看看我们的搜寻结果是否包含足够的信息。具体如下图

如果第一个问题定义好了以后,那第二个问题怎么办呢。 但是我们一样需要去穷举所有的, 来看哪个可以让值最大。
这个怎么办呢?假设这个问题已经被解决了
假装第二个问题已经被解决的情况下,我们就进入第三个问题。
有一堆的Training data:,我希望找到一个function ,其实是希望找到一个,怎么找到这个使得以下条件被满足:
对所有的training data而言,希望正确的应该大过于其他的任何。

用比较具体的例子来说明,假设我现在要做的object detection,我们收集了一张image ,然后呢,知道所对应的,我们又收集了另外一张图片,对应的框框也标出。对于第一张图,我们假设所形成的feature是红色这个点,其他的y跟所形成的是蓝色的点。红色的点只有一个,蓝色的点有好多好多。

假设所形成的feature是红色的星星,与其他的y所形成的是蓝色的星星。可以想象,红色的星星只有一个,蓝色的星星有无数个。把它们画在图上,假设它们是如下图所示位置

我们所要达到的任务是,希望找到一个,那这个可以做到什么事呢?我们把这上面的每个点,红色的星星,红色的圈圈,成千上万的蓝色圈圈和蓝色星星通通拿去和做inner cdot后,我得到的结果是红色星星所得到的大过于所有蓝色星星,红色的圈圈大过于所有红色的圈圈所得到的值。
不同形状之间我们就不比较。圈圈自己跟圈圈比,星星自己跟星星比。做的事情就是这样子,也就是说我希望正确的答案结果大于错误的答案结果,即。

你可能会觉得这个问题会不会很难,蓝色的点有成千上万,我们有办法找到这样的吗?这个问题没有我们想象中的那么难,以下我们提供一个演算法。
输入:训练数据
输出:权重向量
假设我刚才说的那个要让红色的大于蓝色的vector,只要它存在,用这个演算法可以找到答案。
这个演算法是长什么样子呢?这个演算法的input就是我们的training data,output就是要找到一个vector ,这个vector 要满足我们之前所说的特性。
一开始,我们先initialize ,然后开始跑一个循环,这个循环里面,每次我们都取出一笔training data ,然后我们去找一个,它可以使得的值最大,那么这个事情要怎么做呢?
这个问题其实就是Problem 2,我们刚刚假设这个问题已经解决了的,如果找出来的不是正确答案,即,代表这个不是我要的,就要把这个改一下。
怎么改呢?把计算出来,把也计算出来,两者相减在加到上,update 。
有新的后,再去取一个新的example,然后重新算一次max,如果算出来不对再update,步骤一直下去,如果我们要找的是存在的,那么最终就会停止。

这个算法有没有觉得很熟悉呢?这就是perceptron algorithm。perceptron 做的是二元分类, 其实也是structured learning 的一个特例,它们的证明几乎是一样的。
举个例子来说明一下,刚才那个演算法是怎么运作的。
我们的目标是要找到一个,它可以让红色星星大过蓝色星星,红色圈圈大过蓝色圈圈,假设这个是存在的。首先我们假设,然后我们随便pick 一个example ,根据手上的data 和 去看 哪一个使得的值最大。
现在,不管是谁,所算出来的值都为0,所以结果值都是一样的。那么没关系,我们随机选一个当做就可以。我们假设选了下图的点作为,选出来的,对进行调整,把值减掉的值再和加起来,更新

我们就可以获取到第一个,第二步呢,我们就在选一个example ,穷举所有可能的,计算,找出值最大时对应的,假设选出下图的,发现不等于,按照公式更新,得到一个新的。

然后再取出,得到,对于第一笔就不用更新。再测试第二笔data,发现,也不用更新,等等。看过所有data后,发现不再更新,就停止整个training。所找出的可以让。

下一节会证明这个演算法的收敛性,即演算法会结束。
结构化学习要解决的问题,即需要找到一个强有力的函数 f
- 输入和输出都是结构化的对象;
- 对象可以为:sequence(序列),list(列表),tree(树结构),bounding box(包围框),等等
其中,X是一种对象的空间表示,Y是另一种对象的空间表示。
这些问题有一个Unified Framework,只有两步
第一步:训练
寻找一个函数 F,input是x和y,output是一个real number
: 用来评估对象x和y的兼容性 or 合理性
第二步:推理 or 测试
即给定任意一个x,穷举所有的y,将带入F,找出最适当的y作为系统的输出。
虽然这个架构看起来很简单,但是想要使用的话要回答三个问题
Q1: 评估
Q2: 推理
How to solve the “arg max” problem,y的可能性很多,穷举是一件很困难的事,需要找到某些方法解optimization的问题
Q3: 训练
有比找框框更复杂的问题,比如画出物体轮廓,找出人的动作,甚至不只是image processing的问题,这些问题都可以套用接下来的解法。

Q1: Evaluation
Q2: Inference
即给定一张图片x,穷举出所有可能的标记框y,对每一对(x, y),用计算出一对分数最大的(x, y),我们就把对应的y作为输出。
算法的选择取决于task,也取决于
对于Object Detection可以选择的解决方法有
Sequence Labeling
Genetic Algorithm(基因演算)
开放问题:What happens if the inference is non exact? 对结果影响会有多大呢?这件事目前还没有太多讨论。
Q3: Training
Principle
对所有的training data而言,希望正确的应该大过于其他的任何。
假定我们已经解决了Q1和Q2,只关注Q3如何处理:找到最佳的。

Separable:存在一个权值向量,使得:
红色代表正确的特征点(feature point),蓝色代表错误的特征点(feature point),可分性可以理解为,我们需要找到一个权值向量,其与 做内积(inner product) ,能够让正确的point比蓝色的point的值均大于一个。
如果可以找到的话,就可以用以下的演算法找出w

输入:训练数据集
输出:可以让data point separate 的 weight vector w
算法:首先我们假设,然后我们随便pick 一个example ,根据手上的data 和 去看 哪一个使得的值最大。假设选出来的,对进行调整,把值减掉的值再和加起来,更新。不断进行iteration,当对于所有data来说,找到的与都相等,不再更新,就停止整个training。所找出的可以让。
问题是这个演算法要花多久的时间才可以收敛,是否可以轻易的找到一个vector把蓝色的点和红色的点分开?
结论:在可分情形下,我们最多只需更新次就可以找到。其中,为margin(使得误分的点和正确的点能够线性分离),为 与 的最大距离,与y的space无关,因此蓝色的点非常多也不会影响我们update的次数。
一旦有错误产生,w将会被更新
注意:此处我们仅考虑可分情形
假定存在一个权值向量使得对于(所有的样本)、(对于一个样本的所有不正确的标记)
不失一般性,假设
证明:随着k的增加与之间的角度将会变小,会越来越大
在可分情形下,有
所以得到
可得:
分子项不断增加
考虑分母,的长度
则:
其中,
由于w是错误的,和此时找出的内积要大于与正确的内积,因此第二个式子是小于零。
我们假设任意两个特征向量之间的距离小于R,则有
于是
综上可以得到
则
因此随着k的增加,的lower bound也在增加,并且
即得到

单纯把feature×2,随着的增大,也会增大,因此training不会变快
虽然可能没有任何一个vector可以让正确和错误答案完全分开,但是还是可以鉴别出vector的好坏。比如下图左就比右要好。

定义一个成本函数C来评估w的效果有多差,然后选择w,从而最小化成本函数C。
第n笔data的Cost为,在此w下,与最匹配的的分数减去真实的的分数
What is the minimum value?
Other alternatives?
Problem 2中已经计算出了第一名的值是多少,因此用第一名的值减去最方便,其他的方案,比如用前三名的值,需要算出前三名的结果才可以
Find w minimizing the cost 𝐶
我们只需要算出的梯度,就可以利用梯度下降法,但是式子中有,如何求梯度?

当w不同时,得到的也会改变;假设w的space被切割成好几块,得到的分别等于,在边界的地方没有办法微分,但是在每一个region里面都是可以微分的。得到的梯度如图中黄色方框中。
利用(Stochastic) Gradient Descent求解

当学习率设为1时,就转换为structured perceptron。
在刚才,所有错误是视为一样的,然而不同的错误之间是存在差异的,错误可以分为不同的等级,我们在训练时需要考虑进去。比如框在樱花树上分数会特别低,框在凉宫春日脸上,分数会比较高,接近正确的分数也是可以的。如果有一个w只知道把正确的摆在第一位;相反另一个w,可以按照方框好坏来排序,那learn到的结果是比较安全的,因为分数比较高的和第一名差距没有很大。

错误的结果和正确的结果越像,那么分数的差距比较小;相反,差距就比较大。问题是如何衡量这种差异呢?

(正确的标记)与某一个之间的差距定义为(>0),如果和真实结果相同,具体形式根据任务不同而不同。
在下面的讨论中我们定义为

修改Cost Function,本来的Cost是取分数最高的的分数减去得到的分数;
我们会把y的分数加上,这样可以使得当存在与最匹配的y分数大,margin也大的项时,Cost会很大,当分数大,小,我们才认为他是真正的比较好的。
当很大时,我们希望他的分数很小;当很小时,即使它的分数高也没有关系。margin越大,也就说明和真实之间的差距越大,损失也就越大,当然你可以定其他的差距式子,定的好不好可能会影响损失函数的结果。
什么时候Cost最小?当真实值比最大的y+margin的值还要大时,Cost最小。


我们也可以从另外一个角度来分析,最小化新的目标函数,其实就是最小化训练集里的损失上界,我们想最小化我们的最大y和真实y之间的差距本来是这样的,假设我们的output是,希望minimize 。
但是这个很难,因为可能是任何的函数,比如阶梯状函数,就不好微分了,梯度下降法就不好做了,比如语音识别,就算w有改变,但是不一定就有改变,可能要到某个点上才可能会出现变化。所以我们就最小化它的上界,或许没办法让他变小,至少不会变大。

那接下来就是证明上面的式子为什么最小化新的代价函数,就是在最小化训练集上误差的上界:
只需要证明:

也可以满足下式
Margin Rescaling(间隔调整)
Slack Variable Rescaling(松弛变量调整)
训练数据和测试数据可以有不同的分布;
如果w与0比较接近,那么我们就可以最小化误差匹配的影响;
即在原来的基础上,加上一个正则项,为权衡参数;

每次迭代,选择一个训练数据

得到的结果类似于DNN中的weight decay

注意:第二个蓝色箭头并不完全等价,当最小化时等价。
一般我们将用代替之,表示松弛变量,此时条件变成了Find minimizing

单独讨论时的情况,得到新的表达式

我们希望分数差大于margin

我们可能找不到一个w满足以上所有的不等式都成立。

因此将margin减去一个(为了放宽限制,但限制不应过宽,否则会失去意义,越小越好,且要大于等于0)
假设,我们现在有两个训练数据:
对于而言,我们希望正确的分数减去错误的分数大于它们之间的减去,同时满足
对于而言,同理,我们希望正确的分数减去错误的分数,要求大于它们之间的减去,同时满足:
在满足以上这些不等式的前提之下,我们希望是最小的,同时加上对应的正则项也满足最小化。

我们的目标是,求得,最小化C
同时,要满足:
对所有的训练样本的所有不是正确答案的标记,

可以利用SVM包中的solver来解决以上的问题;是一个二次规划(Quadratic Programming QP)的问题;但是约束条件过多,需要通过切割平面算法(Cutting Plane Algorithm)解决受限的问题。
在和组成的参数空间中,颜色表示C的值,在没有限制的情况下,和越小越好,在有限制的情况下,只有内嵌的多边形区域内是符合约束条件的,因此需要在该区域内寻找最小值,即


虽然有很多约束条件,但它们中的大多数的约束都是冗元,并不影响问题的解决;
原本是穷举,而现在我们需要移除那些不起作用的线条,保留有用的线条,这些有影响的线条集可以理解为Working Set,用表示。
Elements in working set is selected iteratively

Strategies of adding elements into working set

假设初始值为空集合null,即没有任何约束限制,求解QP的结果就是对应的蓝点,但是不能满足条件的线条有很多很多,我们现在只找出没有满足的最“严重的”那一个即可。那么我们就把
根据新获得的Working Set中唯一的成员y',找寻新的最小值,进而得到新的w,尽管得到新的w和最小值,但依旧存在不满足条件的约束,需要继续把最难搞定的限制添加到有效集中,再求解一次。得到新的w,直到所有难搞的线条均添加到Working Set之中,最终Working Set中有三个线条,根据这些线条确定求解区间内的point,最终得到问题的解。

Cutting Plane Algorithm
给定训练数据集
Working Set初始设定为
重复以下过程
直到Working Set中的元素不再发生变化,迭代终止,即得到要求解的w。






结构化SVM是线性结构的,如果想要结构化SVM的表现更好,我们需要定义一个较好的特征,但是人为设定特征往往十分困难,一个较好的方法是利用DNN生成特征,先用一个DNN,最后训练的结果往往十分有效。

将DNN与结构化SVM一起训练,同时更新DNN与结构化SVM中的参数。

用一个DNN代替结构化SVM,即将x和y作为输入,(为一个标量)作为输出。

序列标注的问题可以理解为:机器学习所要寻找的目标函数的输入是一个序列,输出也为一个序列,并且假设输入输出的序列长度相同,即输入可以写成序列向量的形式,输出也为序列向量。该任务可以利用循环神经网络来解决,但本章节我们可以基于结构化学习的其它方法进行解决(两步骤,三问题)。
词性标记(POS tagging)
如果不考虑序列,问题就无法解决(POS tagging仅仅依靠查表的方式是不够的,比如Hash Table,你需要知道一整个序列的信息,才能有可能把每个词汇的词性找出)
John saw the saw.
Step 1
假设你大脑中一个马尔科夫链,开始说一句话时,放在句首的词性有50%的可能性为冠词,40%的可能性为专有名词,10%的可能性为动词,然后进行随机采样,再从专有名词开始,有80%的可能性后面为动词,动词后面有25%的可能性为冠词,冠词后面有95%的可能性为名词,名词后面有10%的可能性句子就结束了。
Step 2
根据词性找到词典中中对应的词汇,从不同的词性集合中采样出不同词汇所出现的机率。 HMM可以描述为利用POS标记序列得到对应句子的机率,即

对应于:
其中,
Step2(Emission probability)
我们如何知道P(V|PN), P(saw|V)......?
其中,计算,下一个标记为的机率,就等价于现在训练集里面s出现的次数除去s后面跟s'的次数;
计算某一个标记为s所产生的词为t的机率,就等价于s在整个词汇中出现的次数除去某个词标记为t的次数。
We can compute P(x,y)
给定x(Observed),发现y(Hidden),即如何计算P(x, y)的问题
given x, find y
穷举所有可能的y
利用维特比算法解决此类问题
该评估函数可以理解为x与y的联合概率。
给定一个x,求出最大的y,使得我们定义函数的值达到最大(即维特比算法)。
从训练数据集中得到与
该过程就是计算机率的问题或是统计语料库中词频的问题。
在推理过程
把求解最大的y作为我们的输出值。
为了得到正确的结果,我们需要让
但是HMM可能无法处理这件事情,它不能保证错误的y带进去得到的P(x,y)一定是小的。

假设我们知道在时刻词性标记为N,即,在时刻我们看到的单词为a,现在需要求出
根据计算可以得到V的机率是0.45,D的机率是0.1。但是如果测试数据中有9个,9个,1个,里面存有和训练数据一样的数据,因此D更合理。

通常情况下,隐马尔可夫模型是判断未知数据出现的最大可能性,即(x,y)在训练数据中从未出现过,但也可能有较大的概率P(x,y);
当训练数据很少的时候,使用隐马尔可夫模型,其性能表现是可行的,但当训练集很大时,性能表现较差;
隐马尔可夫模型会产生未卜先知的情况,是因为转移概率和发散概率,在训练时是分开建模的,两者是相互独立的,我们也可以用一个更复杂的模型来模拟两个序列之间的可能性,但要避免过拟合。
条件随机场的模型和隐马尔可夫模型是一样的,同时可以克服隐马尔可夫模型的缺点。
条件随机场模型描述的也是的问题,但与HMM表示形式很不一样(本质上是在训练阶段不同),其机率正比于。
HMM
取对数
其中,

每个单词都已经标记成对应的词性,我们分别计算出 D,N,V 在(x, y)对中出现的次数
然后计算所有的机率相乘的结果,如上图,整理之后的结果为

分析的其他项
其中,黄色表示对所有词性s放在句首的机率取对数,再乘上在(x, y)对中,s放在句首所出现的次数;
绿色表示计算s后面跟s'在(x, y)里面所出现的次数,再乘上s后面跟s'的机率取对数;
紫色同理,最后一项表示两项相乘的形式。
则有

等价于两个向量做内积,进而可以用表示,第二个向量每一个element是依赖于(x, y)的,因此可以写成
由此可知,,其中每一个w,都对应着HMM模型中的某一个机率取对数。
因此对于每一个w,取exponential就可以变为机率。但是我们在训练时对w没有任何限制,得到w大于0时,机率会大于一。
因此需要把表达式变化为

的形式是什么样的?分为两部分
Part 1:relations between tags and words

如果有|S|个可能的标记,|L|个可能的单词,Part 1的维度为 |S| X |L|,value表示在(标记, 单词)对中出现的次数,所以这是一个维度很大的稀疏vector;
Part 2:标签之间的关系

定义为标记s和s'在(x, y)对中连续出现的次数,如果有|S|个可能的标记,这部分向量维度为|S| X |S| + 2|S|(s之间、start、end)。
CRF中可以自己定义
给定训练数据:
找到一个权重向量去最大化目标函数;
其中,与目标函数定义如下:
表示为我们要寻找一个w,使得最大化给定的所产生正确标记的机率,再取对数进行累加,此处可以联想到交叉熵也是最大化正确维度的机率再取对数,只不过此时是针对整个序列而言的。
对做相应的转换

根据CRF的定义可知,可以分解为两项再分别取对数,即最大化观测到的机率,最小化没有观测到的机率。
梯度下降:找到一组参数θ,最小化成本函数,即梯度的反方向
梯度上升:找到一组参数θ,最大化成本函数,即梯度的同方向


求偏导



偏导求解得到两项:
第一项为单词t被标记为s,在中出现的次数;
第二项为累加所有可能的y,每一项为 单词t被标记成s在与任意y的pair里面出现的次数乘上给定下产生这个y的机率。
实际意义解释
对所有的权值向量来说,更新过程是:正确的所形成的的向量减去任意一个y'形成的的向量乘上y‘的机率。


等同于找一个y,使得机率最大,因为由可知。
CRF增加,减少(HMM做不到这一点)
如果要得到正确的答案,我们希望
条件随机场更有可能得到正确的结果。
CRF可能会想办法调整参数,把V产生a的机率变小,让正确的机率变大,错误的变小。

输入输出分别为:
从混合顺序隐马尔科夫模型生成数据
转移概率
取1时,变为一般的隐马尔科夫模型,其值可以任意地进行调整。
发散概率
如果取1时,变为一般的隐马尔科夫模型。

从左下方到右上方不断减小,每一个圈圈表示不同的所得到的结果,对每一个点都做一个隐马尔科夫模型与条件随机场的实验,横轴代表隐马尔科夫模型犯错的百分比,纵轴表示条件随机场犯错的百分比。
当模型与假设不合的时候,CRF比HMM得到了更好的结果


的式子,可以写成对数相加形式。
x, y假设都为序列,可以用条件随机场模型来定义;
Problem 2 利用维特比算法求解即可;
训练时,对所有的训练数据n,以及对所有的,我们希望:
在每个iteration里面,我们会根据目前的w,找到一个,使得:
然后,更新w
即正确的减去其他的所形成的向量。

只减去机率最大的y的特征向量
减去了所有的y'所形成的特征向量与对应的机率做weighted sum

目标函数需要考虑到间隔和误差,训练时可以采用梯度下降法,也可以作为QP问题,因为限制条件过多,所以采用切割平面算法解。

Error function
在下图示例情况下,把Δ定义成错误率,Problem 2.1可以通过维特比算法求解。

POS
命名实体识别(把tag换成公司名/地名/人名等)


最后总结来看,RNN/LSTM在deep这件事的表现其实会比较好,同时在SOTA上,RNN是不可或缺的,如果只是线性的模型,function space就这么大,就算可以直接最小化一个错误的上界,但是这样没什么,因为所有的结果都是坏的,所以相比之下,deep learning占到很大的优势。

底层(埋在土里的萝卜)
叶子
语音识别

其实加上HMM在语音辨识里很有帮助,就算是用RNN,但是在辨识的时候,常常会遇到问题,假设我们是一个frame,用RNN来问这个frame属于哪个form,往往会产生奇怪的结果,比如说一个frame往往是蔓延好多个frame,比如理论是是看到第一个frame是A,第二个frame是A,第三个是A,第四个是A,然后BBB,但是如果用RNN做的时候,RNN每个产生的label都是独立的,所以可能会若无其事的改成B,然后又是A,RNN很容易出现这个现象。HMM则可以把这种情况修复。因为RNN在训练的时候是每个frame分来考虑的,因此不同地方犯的错误对结果的影响相同,结果就会不好,如果想要不同,加上结构化学习的概念才可以做到。所以加上结构化学习的概念会很有帮助。
Semantic Tagging
从RNN的输出结果中,抽出新的特征再计算;作为评估函数
训练阶段
利用梯度下降法让w和循环神经网络中的所有参数一起训练;
测试阶段
找一个y,使得的结果最大化,但此时的x不是input x,而是来自于循环神经网络的输出结果。

structured learning需要解三个问题,其中problem 2往往很困难,因为要穷举所有的y让其最大,解一个optimization的问题,大部分状况都没有好的解决办法。所有有人说structured learning应用并不广泛,但是未来未必是这样的。

其实GAN就是一种structured learning。可以把discriminator看做是evaluation function(也就是problem 1)我们要解一个inference的问题(problem 2),我们要穷举我们未知的东西,看哪个可以让我们的evaluation function最大。这步往往比较困难,因为x的可能性太多了。但这个东西可以就是generator,我们可以想成generator就是给出一个noise,输出一个object,它输出的这个object,就是让discriminator分辨不出的object,如果discriminator就是evaluation function的话,那output的值就是让evaluation function的值很大的那个对应值。所以这个generator就是在解problem 2,其实generator的输出就是argmax的输出,可以把generator当做在解inference这个问题。Problem 3的solution就是train GAN的方法。
在 structured SVM 的 training 里面,我们每次找出最 competitive 的那些 example,然后我们希望正确的 example的 evaluation function 的分数大过 competitive 的 example,然后 update 我们的 model,然后再重新选 competitive 的 example,然后再让正确的,大过 competitive,就这样 iterative 去做。
GAN 的 training 是我们有正确的 example,它应该要让 evaluation function 的值比 Discriminator 的值大,然后我们每次用这个 Generator,Generate 出最competitive 的那个 x,也就是可以让 Discriminator 的值最大的那个 x,然后再去 train Discriminator。Discriminator 要分辨正确的跟 Generated 的。也就是 Discriminator 要给 real 的 example 比较大的值,给那些 most competitive 的 x 比较小的值,然后这个 process 就不断的 iterative 的进行下去,你会 update 你的 Discriminator ,然后 update 你的 Generator。
其实这个跟 Structured SVM 的 training 是有异曲同工之妙的。
我们在讲 structured SVM 的时候都是有一个 input/output,有一个 x 有一个 y; GAN 只有 x,听起来好像不太像,那我们就另外讲一个像的。
GAN也可以是conditional的GAN,example 都是 x,y 的 pair,现在的任务是,given x 找出最有可能的 y。

比如语音辨识,x是声音讯号,y是辨识出来的文字,如果是用conditional的概念,generator输入一个x,就会output一个y,discriminator是去检查y的pair是不是对的,如果给他一个真正的x,y的pair,会得到一个比较高的分数,给一个generator输出的一个y配上输入的x所产生的一个假的pair,就会给他一个比较低的分数。
训练的过程就和原来的GAN就是一样的,这个已经成功运用在文字产生图片这个task上面。这个task的input就是一句话,output就是一张图,generator做的事就是输入一句话,然后产生一张图片,而discriminator要做的事就是给他一张图片和一句话,要他判断这个x,y的pair是不是真的,如果把 discriminator换成evaluation function,把generator换成解inference的problem,其实conditional GAN和structured learning就是可以类比,或者说GAN就是训练structured learning model 的一种方法。
很多人都有类似的想法,比如GAN 可以跟 energy based model 做 connection,可以视为 train energy based model 的一种方法。所谓 energy based model,它就是 structured learning 的另外一种称呼。
Generator 视做是在做 inference 这件事情,是在解 arg max 这个问题,听起来感觉很荒谬。但是也有人觉得一个 neural network ,它有可能就是在解 arg max 这个 problem,这里也给出一些Reference。
所以也许 deep and structured 就是未来一个研究的重点的方向。


